from copy import deepcopy
from unittest.mock import patch

from django.core.exceptions import ValidationError
from django.db.transaction import atomic
from django.test import TestCase
from django.test.testcases import TransactionTestCase
from netjsonconfig import OpenWrt
from swapper import load_model

from openwisp_users.tests.utils import TestOrganizationMixin
from openwisp_utils.tests import catch_signal

from .. import settings as app_settings
from ..base.config import logger as config_model_logger
from ..signals import config_backend_changed, config_modified, config_status_changed
from .utils import CreateConfigTemplateMixin, CreateDeviceGroupMixin, TestVpnX509Mixin

Config = load_model('config', 'Config')
Device = load_model('config', 'Device')
Template = load_model('config', 'Template')
Vpn = load_model('config', 'Vpn')
Ca = load_model('django_x509', 'Ca')

class TestConfig(
    CreateConfigTemplateMixin,
    CreateDeviceGroupMixin,
    TestOrganizationMixin,
    TestVpnX509Mixin,
    TestCase,
):
    """
    tests for Config model
    """

    fixtures = ['test_templates']
    maxDiff = None

    def test_str(self):
        c = Config()
        self.assertEqual(str(c), str(c.pk))
        c = Config(device=Device(name='test'))
        self.assertEqual(str(c), 'test')

    def test_config_not_none(self):
        c = Config(
            device=self._create_device(), backend='netjsonconfig.OpenWrt', config=None
        )
        c.full_clean()
        self.assertEqual(c.config, {})

    def test_backend_class(self):
        c = Config(backend='netjsonconfig.OpenWrt')
        self.assertIs(c.backend_class, OpenWrt)

    def test_backend_instance(self):
        config = {'general': {'hostname': 'config'}}
        c = Config(backend='netjsonconfig.OpenWrt', config=config)
        self.assertIsInstance(c.backend_instance, OpenWrt)

    def test_error_reason_clean(self):
        config = self._create_config(organization=self._get_org())
        config.error_reason = 'e' * 1030
        config.full_clean()
        self.assertEqual(len(config.error_reason), 1024)
        self.assertEqual(config.error_reason[1013:], '[truncated]')

    def test_error_reason_status_error_modified(self):
        error_reason = 'Configuration cannot be applied.'
        config = self._create_config(organization=self._get_org())
        self.assertEqual(config.status, 'modified')
        self.assertEqual(config.error_reason, '')

        with self.subTest('Test configuration status changes to modified'):
            config.set_status_error(reason=error_reason)
            self.assertEqual(config.status, 'error')
            self.assertEqual(config.error_reason, error_reason)
            config.set_status_modified()
            self.assertEqual(config.status, 'modified')
            self.assertEqual(config.error_reason, '')

        with self.subTest('Test configuration status changes to applied'):
            config.set_status_error(reason=error_reason)
            self.assertEqual(config.status, 'error')
            self.assertEqual(config.error_reason, error_reason)
            config.set_status_applied()
            self.assertEqual(config.status, 'applied')
            self.assertEqual(config.error_reason, '')

    @patch.object(app_settings, 'DSA_DEFAULT_FALLBACK', False)
    @patch.object(
        app_settings,
        'DSA_OS_MAPPING',
        {
            'netjsonconfig.OpenWrt': {
                '>=21.02': [r'MyCustomFirmware 2.1(.*)'],
                '<21.02': [r'MyCustomFirmware 2.0(.*)'],
            }
        },
    )
    def test_backend_openwrt_different_versions(self):
        with self.subTest('DSA enabled OpenWrt firmware'):
            c = Config(
                backend='netjsonconfig.OpenWrt',
                device=Device(name='test', os='OpenWrt 21.02.2 r16495-bf0c965af0'),
            )
            self.assertIsInstance(c.backend_instance, OpenWrt)
            self.assertEqual(c.backend_instance.dsa, True)

        with self.subTest('DSA disabed OpenWrt Firmware'):
            c = Config(
                backend='netjsonconfig.OpenWrt',
                device=Device(name='test', os='OpenWrt 19.02.2 r16495-bf0c965af0'),
            )
            self.assertIsInstance(c.backend_instance, OpenWrt)
            self.assertEqual(c.backend_instance.dsa, False)

        with self.subTest('DSA enabled custom firmware'):
            c = Config(
                backend='netjsonconfig.OpenWrt',
                device=Device(name='test', os='MyCustomFirmware 2.1.2'),
            )
            self.assertIsInstance(c.backend_instance, OpenWrt)
            self.assertEqual(c.backend_instance.dsa, True)

        with self.subTest('DSA disabled custom firmware'):
            c = Config(
                backend='netjsonconfig.OpenWrt',
                device=Device(name='test', os='MyCustomFirmware 2.0.1'),
            )
            self.assertIsInstance(c.backend_instance, OpenWrt)
            self.assertEqual(c.backend_instance.dsa, False)

        with self.subTest('Device os field is empty'):
            c = Config(
                backend='netjsonconfig.OpenWrt',
                device=Device(name='test', os=''),
            )
            self.assertIsInstance(c.backend_instance, OpenWrt)
            self.assertEqual(c.backend_instance.dsa, False)

    def test_netjson_validation(self):
        config = {'interfaces': {'invalid': True}}
        c = Config(
            device=self._create_device(), backend='netjsonconfig.OpenWrt', config=config
        )
        # ensure django ValidationError is raised
        try:
            c.full_clean()
        except ValidationError as e:
            self.assertIn('Invalid configuration', e.message_dict['__all__'][0])
        else:
            self.fail('ValidationError not raised')

    def test_json(self):
        dhcp = Template.objects.get(name='dhcp')
        radio = Template.objects.get(name='radio0')
        c = self._create_config(
            organization=self._get_org(), config={'general': {'hostname': 'json-test'}}
        )
        c.templates.add(dhcp)
        c.templates.add(radio)
        full_config = {
            'general': {'hostname': 'json-test'},
            'interfaces': [
                {
                    'name': 'eth0',
                    'type': 'ethernet',
                    'addresses': [{'proto': 'dhcp', 'family': 'ipv4'}],
                }
            ],
            'radios': [
                {
                    'name': 'radio0',
                    'phy': 'phy0',
                    'driver': 'mac80211',
                    'protocol': '802.11n',
                    'channel': 11,
                    'channel_width': 20,
                    'tx_power': 8,
                    'country': 'IT',
                }
            ],
        }
        del c.backend_instance
        self.assertDictEqual(c.json(dict=True), full_config)
        json_string = c.json()
        self.assertIn('json-test', json_string)
        self.assertIn('eth0', json_string)
        self.assertIn('radio0', json_string)

    def test_m2m_validation(self):
        # if config and template have a conflicting non-unique item
        # that violates the schema, the system should not allow
        # the assignment and raise an exception
        config = {'files': [{'path': '/test', 'mode': '0644', 'contents': 'test'}]}
        config_copy = deepcopy(config)
        t = Template(name='files', backend='netjsonconfig.OpenWrt', config=config)
        t.full_clean()
        t.save()
        c = self._create_config(organization=self._get_org(), config=config_copy)
        with atomic():
            try:
                c.templates.add(t)
            except ValidationError:
                self.fail('ValidationError raised!')
        t.config['files'][0]['path'] = '/test2'
        t.full_clean()
        t.save()
        c.templates.add(t)

    def test_checksum(self):
        c = self._create_config(organization=self._get_org())
        self.assertEqual(len(c.checksum), 32)

    def test_get_cached_checksum(self):
        c = self._create_config(organization=self._get_org())

        with self.subTest('check cache set'):
            with patch('django.core.cache.cache.set') as mocked_set:
                checksum = c.get_cached_checksum()
                self.assertEqual(len(checksum), 32)
                mocked_set.assert_called_once()

        with self.subTest('check cache get'):
            with patch(
                'django.core.cache.cache.get', return_value=checksum
            ) as mocked_get:
                self.assertEqual(len(c.get_cached_checksum()), 32)
                mocked_get.assert_called_once()

        with self.subTest('ensure fresh checksum is calculated when cache is clear'):
            with patch.object(config_model_logger, 'debug') as mocked_debug:
                c.get_cached_checksum.invalidate(c)
                self.assertEqual(len(c.get_cached_checksum()), 32)
                mocked_debug.assert_called_once()

        with self.subTest(
            'ensure fresh checksum is NOT calculated when cache is present'
        ):
            with patch.object(config_model_logger, 'debug') as mocked_debug:
                self.assertEqual(len(c.get_cached_checksum()), 32)
                mocked_debug.assert_not_called()

        with self.subTest('ensure cache invalidation works'):
            with patch.object(config_model_logger, 'debug') as mocked_debug:
                old_checksum = c.checksum
                c.config['general']['timezone'] = 'Europe/Rome'
                c.full_clean()
                c.save()
                del c.backend_instance
                self.assertNotEqual(c.checksum, old_checksum)
                self.assertEqual(c.get_cached_checksum(), c.checksum)
                mocked_debug.assert_called_once()

        with self.subTest('test cache invalidation when config templates are changed'):
            with patch.object(config_model_logger, 'debug') as mocked_debug:
                old_checksum = c.checksum
                template = self._create_template()
                c.templates.add(template)
                del c.backend_instance
                self.assertNotEqual(c.checksum, old_checksum)
                self.assertEqual(c.get_cached_checksum(), c.checksum)
                mocked_debug.assert_called_once()

    def test_backend_import_error(self):
        """
        see issue #5
        https://github.com/openwisp/django-netjsonconfig/issues/5
        """
        c = Config(device=self._create_device())
        with self.assertRaises(ValidationError):
            c.full_clean()
        c.backend = 'wrong'
        with self.assertRaises(ValidationError):
            c.full_clean()

    def test_default_status(self):
        c = Config()
        self.assertEqual(c.status, 'modified')

    def test_status_modified_after_change(self):
        c = self._create_config(organization=self._get_org(), status='applied')
        self.assertEqual(c.status, 'applied')
        c.refresh_from_db()
        c.config = {'general': {'description': 'test'}}
        c.full_clean()
        c.save()
        self.assertEqual(c.status, 'modified')

    def test_status_modified_after_templates_changed(self):
        c = self._create_config(organization=self._get_org(), status='applied')
        self.assertEqual(c.status, 'applied')
        t = Template.objects.first()
        c.templates.add(t)
        c.refresh_from_db()
        self.assertEqual(c.status, 'modified')
        c.status = 'applied'
        c.save()
        c.refresh_from_db()
        self.assertEqual(c.status, 'applied')
        c.templates.remove(t)
        c.refresh_from_db()
        self.assertEqual(c.status, 'modified')

    def test_status_modified_after_context_changed(self):
        config = self._create_config(
            organization=self._get_org(),
            status='applied',
            config={'interfaces': [{'name': 'eth0', 'type': '{{ interface_type }}'}]},
            context={'interface_type': 'ethernet'},
        )
        config.refresh_from_db()
        self.assertEqual(config.status, 'applied')

        with self.subTest('Test changing unused configuration variable'):
            config.context.update({'interface_name': 'eth1'})
            config.full_clean()
            config.save()
            config.refresh_from_db()
            self.assertEqual(config.status, 'applied')

        with self.subTest('Test changing used configuration variable'):
            config.context = {'interface_type': 'virtual'}
            config.full_clean()
            config.save()
            config.refresh_from_db()
            self.assertEqual(config.status, 'modified')

    def test_auto_hostname(self):
        c = self._create_config(device=self._create_device(name='automate-me'))
        expected = {'general': {'hostname': 'automate-me'}}
        self.assertDictEqual(c.backend_instance.config, expected)
        c.refresh_from_db()
        self.assertDictEqual(c.config, {'general': {}})

    def test_config_context(self):
        config = {
            'general': {
                'id': '{{ id }}',
                'key': '{{ key }}',
                'name': '{{ name }}',
                'mac_address': '{{ mac_address }}',
            }
        }
        c = Config(
            device=self._create_device(name='context-test'),
            backend='netjsonconfig.OpenWrt',
            config=config,
        )
        output = c.backend_instance.render()
        self.assertIn(str(c.device.id), output)
        self.assertIn(c.device.key, output)
        self.assertIn(c.device.name, output)
        self.assertIn(c.device.mac_address, output)

    def test_context_validation(self):
        config = Config(
            device=self._create_device(name='context-test'),
            backend='netjsonconfig.OpenWrt',
            config={},
        )

        for value in [None, '', False]:
            with self.subTest(f'testing {value} in config.context'):
                config.context = value
                config.full_clean()
                self.assertEqual(config.context, {})

        for value in [['a', 'b'], '"test"']:
            with self.subTest(
                f'testing {value} in config.context, expecting validation error'
            ):
                config.context = value
                with self.assertRaises(ValidationError) as context_manager:
                    config.full_clean()
                message_dict = context_manager.exception.message_dict
                self.assertIn('context', message_dict)
                self.assertIn(
                    'the supplied value is not a JSON object', message_dict['context']
                )

    @patch.dict(app_settings.CONTEXT, {'vpnserver1': 'vpn.testdomain.com'})
    def test_context_setting(self):
        config = {'general': {'vpnserver1': '{{ vpnserver1 }}'}}
        c = Config(
            device=self._create_device(), backend='netjsonconfig.OpenWrt', config=config
        )
        output = c.backend_instance.render()
        vpnserver1 = app_settings.CONTEXT['vpnserver1']
        self.assertIn(vpnserver1, output)

    def test_mac_address_as_hostname(self):
        c = self._create_config(device=self._create_device(name='00:11:22:33:44:55'))
        self.assertIn('00-11-22-33-44-55', c.backend_instance.render())

    def test_create_vpnclient(self):
        vpn = self._create_vpn()
        t = self._create_template(name='test-network', type='vpn', vpn=vpn)
        c = self._create_config(device=self._create_device(name='test-create-cert'))
        c.templates.add(t)
        c.save()
        vpnclient = c.vpnclient_set.first()
        self.assertIsNotNone(vpnclient)
        self.assertEqual(c.vpnclient_set.count(), 1)
        self.assertEqual(vpnclient.config, c)
        self.assertEqual(vpnclient.vpn, vpn)

    def test_delete_vpnclient(self):
        self.test_create_vpnclient()
        c = Config.objects.get(device__name='test-create-cert')
        t = Template.objects.get(name='test-network')
        c.templates.remove(t)
        c.save()
        vpnclient = c.vpnclient_set.first()
        self.assertIsNone(vpnclient)
        self.assertEqual(c.vpnclient_set.count(), 0)

    def test_clear_vpnclient(self):
        self.test_create_vpnclient()
        c = Config.objects.get(device__name='test-create-cert')
        c.templates.clear()
        c.save()
        vpnclient = c.vpnclient_set.first()
        self.assertIsNotNone(vpnclient)
        self.assertNotEqual(c.vpnclient_set.count(), 0)

    def test_multiple_vpn_clients(self):
        vpn1 = self._create_vpn(name='vpn1')
        vpn2 = self._create_vpn(name='vpn2')
        template1 = self._create_template(name='vpn1-template', type='vpn', vpn=vpn1)
        template2 = self._create_template(name='vpn2-template', type='vpn', vpn=vpn2)
        config = self._create_config(device=self._create_device())

        config.templates.add(template1)
        self.assertEqual(config.vpnclient_set.count(), 1)
        config.templates.set((template1, template2))
        self.assertEqual(config.vpnclient_set.count(), 2)

    def test_create_cert(self):
        vpn = self._create_vpn()
        t = self._create_template(
            name='test-create-cert', type='vpn', vpn=vpn, auto_cert=True
        )
        c = self._create_config(device=self._create_device(name='test-create-cert'))
        c.templates.add(t)
        vpnclient = c.vpnclient_set.first()
        self.assertIsNotNone(vpnclient)
        self.assertTrue(vpnclient.auto_cert)
        self.assertIsNotNone(vpnclient.cert)
        self.assertEqual(c.vpnclient_set.count(), 1)

    def test_automatically_created_cert_common_name_format(self):
        self.test_create_cert()
        c = Config.objects.get(device__name='test-create-cert')
        vpnclient = c.vpnclient_set.first()
        expected_cn = app_settings.COMMON_NAME_FORMAT.format(**c.device.__dict__)
        self.assertIn(expected_cn, vpnclient.cert.common_name)

    def test_automatically_created_cert_not_deleted_post_clear(self):
        self.test_create_cert()
        c = Config.objects.get(device__name='test-create-cert')
        vpnclient = c.vpnclient_set.first()
        cert = vpnclient.cert
        cert_model = cert.__class__
        c.templates.clear()
        self.assertNotEqual(c.vpnclient_set.count(), 0)
        self.assertNotEqual(cert_model.objects.filter(pk=cert.pk).count(), 0)

    def test_automatically_created_cert_deleted_post_remove(self):
        self.test_create_cert()
        c = Config.objects.get(device__name='test-create-cert')
        t = Template.objects.get(name='test-create-cert')
        vpnclient = c.vpnclient_set.first()
        cert = vpnclient.cert
        cert_model = cert.__class__
        c.templates.remove(t)
        self.assertEqual(c.vpnclient_set.count(), 0)
        self.assertEqual(cert_model.objects.filter(pk=cert.pk).count(), 0)

    def test_create_cert_false(self):
        vpn = self._create_vpn()
        t = self._create_template(type='vpn', auto_cert=False, vpn=vpn)
        c = self._create_config(device=self._create_device(name='test-create-cert'))
        c.templates.add(t)
        c.save()
        vpnclient = c.vpnclient_set.first()
        self.assertIsNotNone(vpnclient)
        self.assertFalse(vpnclient.auto_cert)
        self.assertIsNone(vpnclient.cert)
        self.assertEqual(c.vpnclient_set.count(), 1)

    def test_cert_not_deleted_on_config_change(self):
        vpn = self._create_vpn()
        t = self._create_template(type='vpn', auto_cert=True, vpn=vpn)
        c = self._create_config(device=self._create_device(name='test-device'))
        c.templates.add(t)
        c.save()
        vpnclient = c.vpnclient_set.first()
        cert = vpnclient.cert
        cert_model = cert.__class__

        with self.subTest(
            "Ensure that the VpnClient and x509 Cert instance is created"
        ):
            self.assertIsNotNone(vpnclient)
            self.assertTrue(vpnclient.auto_cert)
            self.assertIsNotNone(vpnclient.cert)

        c.templates.clear()
        with self.subTest("Ensure that VpnClient and Cert instance are not deleted"):
            self.assertIsNotNone(c.vpnclient_set.first())
            self.assertNotEqual(c.vpnclient_set.count(), 0)
            self.assertNotEqual(cert_model.objects.filter(pk=cert.pk).count(), 0)

        # add the template again
        c.templates.add(t)
        c.save()
        with self.subTest("Ensure no additional VpnClients are created"):
            self.assertEqual(c.vpnclient_set.count(), 1)
            self.assertEqual(c.vpnclient_set.first(), vpnclient)

    def _get_vpn_context(self):
        self.test_create_cert()
        c = Config.objects.get(device__name='test-create-cert')
        context = c.get_context()
        vpnclient = c.vpnclient_set.first()
        return context, vpnclient

    def test_vpn_context_ca_path(self):
        context, vpnclient = self._get_vpn_context()
        ca = vpnclient.cert.ca
        key = 'ca_path_{0}'.format(vpnclient.vpn.pk.hex)
        filename = 'ca-{0}-{1}.pem'.format(ca.pk, ca.common_name)
        value = '{0}/{1}'.format(app_settings.CERT_PATH, filename)
        self.assertIn(key, context)
        self.assertIn(value, context[key])

    def test_vpn_context_ca_path_bug(self):
        vpn = self._create_vpn(ca_options={'common_name': 'common name CA'})
        t = self._create_template(type='vpn', auto_cert=True, vpn=vpn)
        c = self._create_config(device=self._create_device(name='test-create-cert'))
        c.templates.add(t)
        context = c.get_context()
        ca = vpn.ca
        key = 'ca_path_{0}'.format(vpn.pk.hex)
        filename = 'ca-{0}-{1}.pem'.format(ca.pk, ca.common_name.replace(' ', '_'))
        value = '{0}/{1}'.format(app_settings.CERT_PATH, filename)
        self.assertIn(key, context)
        self.assertIn(value, context[key])

    def test_vpn_context_ca_contents(self):
        context, vpnclient = self._get_vpn_context()
        key = 'ca_contents_{0}'.format(vpnclient.vpn.pk.hex)
        value = vpnclient.cert.ca.certificate
        self.assertIn(key, context)
        self.assertIn(value, context[key])

    def test_vpn_context_cert_path(self):
        context, vpnclient = self._get_vpn_context()
        vpn_pk = vpnclient.vpn.pk.hex
        key = 'cert_path_{0}'.format(vpn_pk)
        filename = 'client-{0}.pem'.format(vpn_pk)
        value = '{0}/{1}'.format(app_settings.CERT_PATH, filename)
        self.assertIn(key, context)
        self.assertIn(value, context[key])

    def test_vpn_context_cert_contents(self):
        context, vpnclient = self._get_vpn_context()
        vpn_pk = vpnclient.vpn.pk.hex
        key = 'cert_contents_{0}'.format(vpn_pk)
        value = vpnclient.cert.certificate
        self.assertIn(key, context)
        self.assertIn(value, context[key])

    def test_vpn_context_key_path(self):
        context, vpnclient = self._get_vpn_context()
        vpn_pk = vpnclient.vpn.pk.hex
        key = 'key_path_{0}'.format(vpn_pk)
        filename = 'key-{0}.pem'.format(vpn_pk)
        value = '{0}/{1}'.format(app_settings.CERT_PATH, filename)
        self.assertIn(key, context)
        self.assertIn(value, context[key])

    def test_vpn_context_key_contents(self):
        context, vpnclient = self._get_vpn_context()
        vpn_pk = vpnclient.vpn.pk.hex
        key = 'key_contents_{0}'.format(vpn_pk)
        value = vpnclient.cert.private_key
        self.assertIn(key, context)
        self.assertIn(value, context[key])

    def test_vpn_context_no_cert(self):
        vpn = self._create_vpn()
        t = self._create_template(type='vpn', auto_cert=False, vpn=vpn)
        c = self._create_config(device=self._create_device(name='test-create-cert'))
        c.templates.add(t)
        c.save()
        context = c.get_context()
        vpn_id = vpn.pk.hex
        cert_path_key = 'cert_path_{0}'.format(vpn_id)
        cert_contents_key = 'cert_contents_{0}'.format(vpn_id)
        key_path_key = 'key_path_{0}'.format(vpn_id)
        key_contents_key = 'key_contents_{0}'.format(vpn_id)
        ca_path_key = 'ca_path_{0}'.format(vpn_id)
        ca_contents_key = 'ca_contents_{0}'.format(vpn_id)
        self.assertNotIn(cert_path_key, context)
        self.assertNotIn(cert_contents_key, context)
        self.assertNotIn(key_path_key, context)
        self.assertNotIn(key_contents_key, context)
        self.assertIn(ca_path_key, context)
        self.assertIn(ca_contents_key, context)

    def test_m2m_str_conversion(self):
        t = self._create_template()
        c = self._create_config(device=self._create_device(name='test-m2m-str-repr'))
        c.templates.add(t)
        c.save()
        through = str(c.templates.through.objects.first())
        self.assertIn('Relationship with', through)
        self.assertIn(t.name, through)

    def test_get_template_model_static(self):
        self.assertIs(Config.get_template_model(), Template)

    def test_get_template_model_bound(self):
        self.assertIs(Config().get_template_model(), Template)

    def test_remove_duplicate_files(self):
        template1 = self._create_template(
            name='test-vpn-1',
            config={
                'files': [
                    {
                        'path': '/etc/vpnserver1',
                        'mode': '0644',
                        'contents': '{{ name }}\n{{ vpnserver1 }}\n',
                    }
                ]
            },
        )
        template2 = self._create_template(
            name='test-vpn-2',
            config={
                'files': [
                    {
                        'path': '/etc/vpnserver1',
                        'mode': '0644',
                        'contents': '{{ name }}\n{{ vpnserver1 }}\n',
                    }
                ]
            },
        )
        config = self._create_config(organization=self._get_org())
        config.templates.add(template1)
        config.templates.add(template2)
        config.refresh_from_db()
        try:
            result = config.get_backend_instance(
                template_instances=[template1, template2]
            ).render()
        except ValidationError:
            self.fail('ValidationError raised!')
        else:
            self.assertIn('# path: /etc/vpnserver1', result)

    def test_duplicated_files_in_config(self):
        try:
            self._create_config(
                organization=self._get_org(),
                config={
                    'files': [
                        {
                            'path': '/etc/vpnserver1',
                            'mode': '0644',
                            'contents': '{{ name }}\n{{ vpnserver1 }}\n',
                        },
                        {
                            'path': '/etc/vpnserver1',
                            'mode': '0644',
                            'contents': '{{ name }}\n{{ vpnserver1 }}\n',
                        },
                    ]
                },
            )
        except ValidationError as e:
            self.assertIn('Invalid configuration triggered by "#/files"', str(e))
        else:
            self.fail('ValidationError not raised!')

    def test_config_with_shared_template(self):
        org = self._get_org()
        config = self._create_config(organization=org)
        # shared template
        template = self._create_template()
        # add shared template
        config.templates.add(template)
        self.assertIsNone(template.organization)
        self.assertEqual(config.templates.first().pk, template.pk)

    def test_config_and_template_different_organization(self):
        org1 = self._get_org()
        org2 = self._create_org(name='test org2', slug='test-org2')
        template = self._create_template(organization=org1)
        config = self._create_config(organization=org2)
        try:
            config.templates.add(template)
        except ValidationError as e:
            self.assertIn('do not match the organization', e.messages[0])
        else:
            self.fail('ValidationError not raised')

    def test_config_status_changed_not_sent_on_creation(self):
        org = self._get_org()
        with catch_signal(config_status_changed) as handler:
            self._create_config(organization=org)
            handler.assert_not_called()

    def test_config_status_changed_modified(self):
        org = self._get_org()
        with catch_signal(config_status_changed) as handler:
            c = self._create_config(organization=org, status='applied')
            handler.assert_not_called()
            self.assertEqual(c.status, 'applied')

        with catch_signal(config_status_changed) as handler:
            c.config = {'general': {'description': 'test'}}
            c.full_clean()
            c.save()
            handler.assert_called_once_with(
                sender=Config, signal=config_status_changed, instance=c
            )
            self.assertEqual(c.status, 'modified')

        with catch_signal(config_status_changed) as handler:
            c.config = {'general': {'description': 'changed again'}}
            c.full_clean()
            c.save()
            handler.assert_not_called()
            self.assertEqual(c.status, 'modified')

    def test_config_modified_sent(self):
        org = self._get_org()
        with catch_signal(config_modified) as handler:
            c = self._create_config(organization=org, status='applied')
            handler.assert_not_called()
            self.assertEqual(c.status, 'applied')

        with catch_signal(config_modified) as handler:
            c.config = {'general': {'description': 'test'}}
            c.full_clean()
            c.save()
            handler.assert_called_once_with(
                sender=Config,
                signal=config_modified,
                instance=c,
                device=c.device,
                config=c,
                previous_status='applied',
                action='config_changed',
            )
            self.assertEqual(c.status, 'modified')

        with catch_signal(config_modified) as handler:
            c.config = {'general': {'description': 'changed again'}}
            c.full_clean()
            # repeated on purpose
            c.full_clean()
            c.save()
            handler.assert_called_once_with(
                sender=Config,
                signal=config_modified,
                instance=c,
                device=c.device,
                config=c,
                previous_status='modified',
                action='config_changed',
            )
            self.assertEqual(c.status, 'modified')

    def test_check_changes_query(self):
        config = self._create_config(organization=self._get_org())
        with self.assertNumQueries(10):
            config._check_changes()

    def test_config_get_system_context(self):
        config = self._create_config(
            organization=self._get_org(), context={'test': 'value'}
        )
        system_context = config.get_system_context()
        self.assertNotIn('test', system_context.keys())

    def test_initial_status(self):
        config = self._create_config(
            organization=self._get_org(), context={'test': 'value'}
        )
        self.assertEqual(config._initial_status, config.status)
        config.status = 'modified'
        config.save()
        self.assertEqual(config._initial_status, 'modified')

    def test_config_backend_changed(self):
        org = self._get_org()
        old_backend = 'netjsonconfig.OpenWrt'
        backend = 'netjsonconfig.OpenWisp'
        group = self._create_device_group(organization=org)
        t1 = self._create_template(name='t1', backend=old_backend)
        t2 = self._create_template(name='t2', backend=backend)
        group.templates.add(*[t1, t2])
        with self.subTest('config_backend_changed signal must not be sent on creation'):
            with catch_signal(config_backend_changed) as handler:
                d = self._create_device(group=group, organization=org)
                handler.assert_not_called()
                self.assertTrue(d.config.templates.filter(pk=t1.pk).exists())
                self.assertFalse(d.config.templates.filter(pk=t2.pk).exists())
        with self.subTest(
            'config_backend_changed signal must not be sent on config status change'
        ):
            with catch_signal(config_backend_changed) as handler:
                c = d.config
                c.status = 'applied'
                c.save(update_fields=['status'])
                handler.assert_not_called()
        with self.subTest(
            'config_backend_changed signal must be sent on backend change'
        ):
            with catch_signal(config_backend_changed) as handler:
                c = d.config
                c.backend = backend
                c.save(update_fields=['backend'])
                handler.assert_called_once_with(
                    sender=Config,
                    signal=config_backend_changed,
                    instance=c,
                    old_backend=old_backend,
                    backend=backend,
                )
                self.assertTrue(d.config.templates.filter(pk=t2.pk).exists())
                self.assertFalse(d.config.templates.filter(pk=t1.pk).exists())

class TestTransactionConfig(
    CreateConfigTemplateMixin,
    TestOrganizationMixin,
    TestVpnX509Mixin,
    TransactionTestCase,
):
    def test_certificate_renew_invalidates_checksum_cache(self):
        config = self._create_config(organization=self._get_org())
        vpn_template = self._create_template(
            name='vpn1-template', type='vpn', vpn=self._create_vpn(), config={}
        )
        config.templates.add(vpn_template)
        config.refresh_from_db()
        with patch('django.core.cache.cache.delete') as mocked_delete:
            # Comparing checksum values after deleting backend instance
            # makes the test bogus. Hence assertion for cache.delete is required
            old_checksum = config.checksum
            vpnclient_cert = config.vpnclient_set.first().cert
            vpnclient_cert.renew()
            # An additional call from cache invalidation of
            # DeviceGroupCommonName View
            self.assertEqual(mocked_delete.call_count, 3)
            del config.backend_instance
            self.assertNotEqual(config.get_cached_checksum(), old_checksum)
            config.refresh_from_db()
            self.assertEqual(config.status, 'modified')


import RPi.GPIO as GPIO
import time
from stockfish import Stockfish

GPIO.setmode(GPIO.BCM)
control1 = 2
control2 = 3
control3 = 4
GPIO.setup(control1, GPIO.OUT)
GPIO.setup(control2, GPIO.OUT)
GPIO.setup(control3, GPIO.OUT)

toggle = 17
GPIO.setup(toggle, GPIO.OUT)

readinput = [27, 22, 10, 9, 11, 5, 6, 13]
for i in readinput:
	GPIO.setup(i, GPIO.IN)

stockfish = Stockfish("/Users/sunke/Work/stockfish_15.1_win_x64_avx2/stockfish_15.1_win_x64_avx2/stockfish-windows-2022-x86-64-avx2.exe")

stockfish.set_fen_position("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")

def get_current_board_pos():
    piece_location = []
    #if a piece is there and 0 if there's no piece
    for i in readinput:
        GPIO.output(toggle, True)
        GPIO.output(toggle, False)
        GPIO.output(control1, False)
        GPIO.output(control2, False)
        GPIO.output(control3, False)
        time.sleep(0.2)
        piece_location.append(GPIO.input(i))

        GPIO.output(toggle, True)
        GPIO.output(toggle, False)
        GPIO.output(control1, False)
        GPIO.output(control2, False)
        GPIO.output(control3, True)
        time.sleep(0.2)
        piece_location.append(GPIO.input(i))

        GPIO.output(toggle, True)
        GPIO.output(toggle, False)
        GPIO.output(control1, False)
        GPIO.output(control2, True)
        GPIO.output(control3, False)
        time.sleep(0.2)
        piece_location.append(GPIO.input(i))

        GPIO.output(toggle, True)
        GPIO.output(toggle, False)
        GPIO.output(control1, False)
        GPIO.output(control2, True)
        GPIO.output(control3, True)
        time.sleep(0.2)
        piece_location.append(GPIO.input(i))

        GPIO.output(toggle, True)
        GPIO.output(toggle, False)
        GPIO.output(control1, True)
        GPIO.output(control2, False)
        GPIO.output(control3, False)
        time.sleep(0.2)
        piece_location.append(GPIO.input(i))

        GPIO.output(toggle, True)
        GPIO.output(toggle, False)
        GPIO.output(control1, True)
        GPIO.output(control2, False)
        GPIO.output(control3, True)
        time.sleep(0.2)
        piece_location.append(GPIO.input(i))

        GPIO.output(toggle, True)
        GPIO.output(toggle, False)
        GPIO.output(control1, True)
        GPIO.output(control2, True)
        GPIO.output(control3, False)
        time.sleep(0.2)
        piece_location.append(GPIO.input(i))

        GPIO.output(toggle, True)
        GPIO.output(toggle, False)
        GPIO.output(control1, True)
        GPIO.output(control2, True)
        GPIO.output(control3, True)
        time.sleep(0.2)
        piece_location.append(GPIO.input(i))
    return piece_location

noPiece = 0
King = 1
Pawn = 2
Knight = 3
Bishop = 4
Rook = 5
Queen = 6
White = 8
Black = 16
pieces = {"r": Black+Rook, "n": Knight+Black, "b": Bishop+Black, "q":Black+Queen, "k":King+Black, "p":Pawn+Black, "R": White+Rook, "N": Knight+White, "B": Bishop+White, "Q":White+Queen, "K":King+White, "P":Pawn+White, " ": 0}

board = []
temp = stockfish.get_board_visual().split("\n")
for i in range(len(temp)-1):
    if temp[i][2]=="-" or temp[i][2]=="a":
        continue
    else:
        for j in range(8):
            board.append(pieces[temp[i][2+j*4]])


import scipy.io, os, random, sys
import numpy as np
import pandas as pd
import torch
import torchvision.datasets
import torchvision.transforms as transforms
import torch.nn.functional as F
from skimage.transform import resize

class Data_Loader:
    def __init__(self):
        return

    def load_dataset(self, dataset_name, true_label=1):
        if dataset_name == "cifar10":
            return self.load_CIFAR10(true_label)
        if dataset_name == "thyroid":
            return self.load_THYROID()
        if dataset_name == "stl10":
            return self.load_STL10(true_label)

    def normalize_img_dataset(self, dataset, mean=1):
        return 2*(dataset/255.)-mean

    def normalize_tabular_dataset(self, x_train, normal_samples, anomal_samples):
        means = x_train.mean(0)
        stds = x_train.std(0)
        stds[stds==0] = 1

        def normalize(xs, mean, stds):
            return np.array([(x-mean)/stds for x in xs])

        x_train = normalize(x_train, means, stds)
        normal_samples = normalize(normal_samples, means, stds)
        anomal_samples = normalize(anomal_samples, means, stds)
        return x_train, normal_samples, anomal_samples

    def load_CIFAR10(self, true_label):
        folder_path = "./data"
        if not os.path.exists(folder_path):
            os.mkdir(folder_path)

        train_dataset = torchvision.datasets.CIFAR10(folder_path, train=True, download=True)
        x_train = np.array(train_dataset.data)
        y_train = np.array(train_dataset.targets)

        test_dataset = torchvision.datasets.CIFAR10(folder_path, train=False, download=True)
        x_test = np.array(test_dataset.data)
        y_test = np.array(test_dataset.targets)

        x_train = x_train[np.where(y_train==true_label)]
        x_train = self.normalize_img_dataset(np.asarray(x_train, dtype="float32"))
        x_test = self.normalize_img_dataset(np.asarray(x_test, dtype="float32"))
        print("Normalized CIFAR dataset is loaded.")
        return x_train, x_test, y_test

    def load_STL10(self, true_label, few=16):
        folder_path = "./data"
        if not os.path.exists(folder_path):
            os.mkdir(folder_path)

        torch.manual_seed(0)
        random.seed(0)
        classes = list(range(10))

        train_dataset = torchvision.datasets.STL10(folder_path, split="train", download=True, transform=transforms.ToTensor())
        selected_index_list = []
        for cls in classes:
            cls_index_list = [i for i in range(len(train_dataset)) if train_dataset[i][1] == cls]
            random.shuffle(cls_index_list)
            selected_index_list.extend(cls_index_list[:few])

        train_dataset = torch.utils.data.Subset(train_dataset, selected_index_list)
        x_train = np.array([train_dataset[i][0].numpy() for i in range(len(train_dataset))])
        y_train = np.array([train_dataset[i][1] for i in range(len(train_dataset))])

        test_dataset = torchvision.datasets.STL10(folder_path, split="test", download=True, transform=transforms.ToTensor())
        x_test = np.array([test_dataset[i][0].numpy() for i in range(len(test_dataset))])
        y_test = np.array([test_dataset[i][1] for i in range(len(test_dataset))])

        x_train = x_train.transpose((0, 2, 3, 1))
        x_test = x_test.transpose((0, 2, 3, 1))

        def resize_dataset(dataset):
            resized = np.zeros((dataset.shape[0], 32, 32, 3))
            for i in range(dataset.shape[0]):
                resized[i] = resize(dataset[i], (32,32))
            return resized

        x_train = resize_dataset(x_train)
        x_test = resize_dataset(x_test)

        x_train = x_train[np.where(y_train==true_label)]
        x_train = self.normalize_img_dataset(np.asarray(x_train, dtype="float32"))
        x_test = self.normalize_img_dataset(np.asarray(x_test, dtype="float32"))
        print("Normalized STL10 dataset is loaded.")
        return x_train, x_test, y_test

    def load_THYROID(self):
        data = scipy.io.loadmat("data/thyroid.mat")
        samples = data['X']
        labels = ((data['y']).astype(np.int32)).reshape(-1)

        normal_samples = samples[labels == 0]
        anomal_samples = samples[labels == 1]

        n_train = len(normal_samples) // 2
        x_train = normal_samples[:n_train]

        normal_test = normal_samples[n_train:]
        anomal_test = anomal_samples
        return self.normalize_tabular_dataset(x_train, normal_test, anomal_test)


from models.transactions import Transaction
from models.category import Category
import pdb
from models.merchant import Merchant
from models.category import Category
from models.profile import Profile
import repositories.merchant_repository as merchant_repository
import repositories.category_repository as category_repository
import repositories.transaction_repositiory as transaction_repository
import repositories.profile_repository as profile_repository

merchant_repository.delete_all()
category_repository.delete_all()
transaction_repository.delete_all()

import datetime
x = datetime.datetime.now()

profile1= Profile(100, 90)
profile_repository.save(profile1)

profile2= Profile(120,80)
profile_repository.save(profile2)

merchant1 = Merchant("Tesco")
merchant_repository.save(merchant1)

merchant2 = Merchant("Sainsburys")
merchant_repository.save(merchant2)

merchant3 = Merchant("Amazon")
merchant_repository.save(merchant3)

category1 = Category("Food", 100)
category_repository.save(category1)

category2 = Category("Entertainment", 50)
category_repository.save(category2)

transaction1 = Transaction(merchant1, category1, "Weekly food shop", 50, x)
transaction_repository.save(transaction1)

transaction2 = Transaction(merchant3, category2, "Purchased a film", 1.99, x)
transaction_repository.save(transaction2)

transaction3 = Transaction(merchant1, category1, "Top up shop", 5, x)
transaction_repository.save(transaction3)

transaction4 = Transaction(merchant2, category2, "video game", 45.99, x)
transaction_repository.save(transaction4)

pdb.set_trace()


#Class of a cost element group
class CostElementGroup:

    # columns used in the csv, in the right order
    _dtb_columns = [
                    "costelementgroup_id",
                    "costelementgroup_name",
                    "classification_id"
                   ]
    # name of the dtb table for this object
    _dtb_table = "groupcostelement"
    # Object(s) which must be included in this object
    _parent_objct = []


import os
from bship_classes import Ship, Board, Player

# Battleship: A programming noob's version of the classic
# by Adam Cameron, April 2017

# Universal variables for various uses

BOARD_SIZE = 10

SHIPS = {
    "a": ("Aircraft Carrier", 5),
    "b": ("Battleship", 4),
    "c": ("Submarine", 3),
    "d": ("Cruiser", 3),
    "e": ("Patrol Boat", 2)
}

COLS = {
    "a": 0,
    "b": 1,
    "c": 2,
    "d": 3,
    "e": 4,
    "f": 5,
    "g": 6,
    "h": 7,
    "i": 8,
    "j": 9
}

TRACKING = {
    'a': 'a',
    'b': 'b',
    'c': 'c',
    'd': 'd',
    'e': 'e'
}

HIT_TRACKING = {
    'a': 'z',
    'b': 'y',
    'c': 'x',
    'd': 'w',
    'e': 'v'
}

# Similar to SHIPS above, but necessary because computer
# needs to be able to delete items from this one.

ship_choices = {
    'a': 'Aircraft Carrier',
    'b': 'Battleship',
    'c': 'Submarine',
    'd': 'Cruiser',
    'e': 'Patrol Boat'
}

VERTICAL_SHIP = '|'
HORIZONTAL_SHIP = '-'
EMPTY = 'O'
MISS = '.'
HIT = '*'
SUNK = '#'

COLUMNS = 'abcdefghij'

def clear_screen():
    """Clear screen"""
    os.system('cls' if os.name == 'nt' else 'clear')

def choice_getter(board, player):
    """Take a choice of which ship to place from the user"""
    ships_to_choose = [
        ['a', 'Aircraft Carrier'],
        ['b', 'Battleship'],
        ['c', 'Submarine'],
        ['d', 'Cruiser'],
        ['e', 'Patrol Boat']
    ]
    letter_choices = {
        'a': 'a', 'b': 'b', 'c': 'c', 'd': 'd', 'e': 'e'
    }

    while ships_to_choose:
        clear_screen()
        print(board)
        print("\n{}, which ship would you like to place?\n".format(player.name))
        for i, j in ships_to_choose:
            print("[{}] {}".format(i, j))
        user_choice = input("\n> ").lower()
        if user_choice in letter_choices.keys():
            for i in ships_to_choose:
                if i[0] == user_choice:
                    ships_to_choose.remove(i)
                    del letter_choices[user_choice]
            ship_placer(board, user_choice, player)

        else:
            input("\nSorry, that's not a valid choice. Hit ENTER to continue...")

def ship_placer(board, choice, player):
    """Place ships on each player's board"""
    clear_screen()
    unplaced = True
    while unplaced:
        clear_screen()
        print(board)
        horiz_vert = input("""
{}, would you like to place your {} horizontally or vertically?
Remember that the {} takes up {} spaces!
Ships will be placed from left to right and from top to bottom.
Please type 'H' for horizontal and 'V' for vertical and press ENTER.\n
>""".format(
    player.name, SHIPS[choice][0], SHIPS[choice][0], SHIPS[choice][1])
).lower()
        if horiz_vert == 'h':
            clear_screen()
            print(board)
            col_choice = input("\nPlease specify a column:\n> ").lower()
            clear_screen()
            print(board)
            row_choice = input("\nPlease specify a row:\n> ")
            try:
                row_choice = int(row_choice)
            except ValueError:
                row_choice = 99
            if row_choice in list(range(1, 11)) and col_choice in COLS.keys():
                if (len(board.board[row_choice-1][COLUMNS.index(col_choice):])
                    >= SHIPS[choice][1] and
                    all(p == EMPTY for p in (board.board[row_choice - 1][COLS[col_choice]:
                        (COLS[col_choice] + SHIPS[choice][1])])) == True):
                    col = COLUMNS.index(col_choice)
                    row = row_choice - 1
                    player.ships[choice].coordinates = [(row, col)]
                    for i in range(player.ships[choice].length - 1):
                        col += 1
                        player.ships[choice].coordinates.append((row, col))
                    for i, j in player.ships[choice].coordinates:
                        board.board[i][j] = HORIZONTAL_SHIP
                    unplaced = False
                else:
                    input(
                        """Sorry, your ship goes off the map or intersects
                        with a previously placed ship. Press ENTER to try again...
                        """)

            else:
                clear_screen()
                print(board)
                input(
                    """\nSorry, your column or row choice was invalid.
                    Please press ENTER to try again...""")
        if horiz_vert == 'v':
            clear_screen()
            print(board)
            col_choice = input("\nPlease specify a column:\n> ").lower()
            clear_screen()
            print(board)
            row_choice = input("\nPlease specify a row:\n> ")
            try:
                row_choice = int(row_choice)
            except ValueError:
                row_choice = 99
            if row_choice in list(range(1, 11)) and col_choice in COLS.keys():
                if player.ships[choice].length <= len(board.board[row_choice - 1:]):
                    holder = []
                    for i in board.board[row_choice - 1:SHIPS[choice][1]]:
                        holder.append(i[COLUMNS.index(col_choice)])
                    if all(p == EMPTY for p in holder):
                        col = COLUMNS.index(col_choice)
                        row = row_choice-1
                        player.ships[choice].coordinates = [(row, col)]
                        for i in range(player.ships[choice].length - 1):
                            row += 1
                            player.ships[choice].coordinates.append((row, col))
                        for i, j in player.ships[choice].coordinates:
                            board.board[i][j] = VERTICAL_SHIP
                        unplaced = False
                    else:
                        clear_screen()
                        print(board)
                        input(
                            """\nSorry, the ship cannot intersect with a previously placed ship.
                            Press ENTER to try again..."""
                            )

                else:
                    clear_screen()
                    print(board)
                    input(
                        """\nSorry, your ship cannot be placed off of the map.
                        Please press ENTER to try again...
                        """)

            else:
                clear_screen()
                print(board)
                input(
                    """\nSorry, your column or row choice was invalid.
                    Please press ENTER to try again...""")

def turn_taker(
    attacker, defender,
    attacker_main, defender_main,
    defender_view):
    """Let each player take a shot at the other's board"""
    shooting = True
    clear_screen()
    input("\nIt's {}'s turn! Please press ENTER when {} has the computer.".format(
        attacker.name, attacker.name))
    while shooting:
        clear_screen()
        print("    {}'s Board\n".format(defender.name))
        print(defender_view)
        print('\n')
        print("    {}'s Board\n".format(attacker.name))
        print(attacker_main)
        col_choice = input("""
            \nTake your best shot, {}!
            Please choose a column:\n> """.format(
            attacker.name)).lower()
        row_choice = input("\nChoose a row:\n> ")
        try:
            row_choice = int(row_choice)
        except ValueError:
            row_choice = 99
        if row_choice in list(range(1, 11)) and col_choice in COLS.keys():
            if (defender_view.board[row_choice-1][COLS[col_choice]] == MISS or
                defender_main.board[row_choice-1][COLS[col_choice]] == HIT):
                clear_screen()
                print("    {}'s Board\n".format(defender.name))
                print(defender_view)
                print('\n')
                print("    {}'s Board\n".format(attacker.name))
                print(attacker_main)
                input("\nYou already fired in that spot! Press ENTER to try again...")
            elif defender_main.board[row_choice-1][COLS[col_choice]] == EMPTY:
                defender_view.board[row_choice-1][COLS[col_choice]] = MISS
                clear_screen()
                print("    {}'s Board\n".format(defender.name))
                print('\n')
                print(defender_view)
                print('\n')
                print("    {}'s Board\n".format(attacker.name))
                print(attacker_main)
                input("\nMiss! Please press ENTER and pass the computer to {}.".format(
                    defender.name))
                shooting = False
            elif defender_view.board[row_choice - 1][COLS[col_choice]] == SUNK:
                clear_screen()
                print("    {}'s Board\n".format(defender.name))
                print(defender_view)
                print('\n')
                print("    {}'s Board\n".format(attacker.name))
                print(attacker_main)
                input("\nYou already fired in that spot! Press ENTER to try again...")
            elif (defender_main.board[row_choice-1][COLS[col_choice]] == VERTICAL_SHIP or
                defender_main.board[row_choice-1][COLS[col_choice]] == HORIZONTAL_SHIP):
                defender_view.board[row_choice-1][COLS[col_choice]] = HIT
                defender_main.board[row_choice-1][COLS[col_choice]] = HIT
                clear_screen()
                print("    {}'s Board\n".format(defender.name))
                print(defender_view)
                print('\n')
                print("    {}'s Board\n".format(attacker.name))
                print(attacker_main)
                input("\nDirect hit! Great job! Hit ENTER to continue...")
                attack = (row_choice - 1, COLUMNS.index(col_choice))
                check_for_sink(attack, attacker, defender,
                               attacker_main, defender_main, defender_view)
                shooting = False
        else:
            input(
                "\nSorry! You need to choose a row between 1-10 and a column! Try again!")

def check_for_sink(
    attack, attacker, defender,
    attacker_main, defender_main,
    defender_view):
    """
    Called at the end of turn_taker(),
    check to see if a player's ship has been sunk
    """
    for key, value in defender.ships.items():
        if attack in value.coordinates and value.hits < value.length:
            value.hits += 1
    for key, value in defender.ships.items():
        if value.hits == value.length and value.sunk == False:
            for i, j in value.coordinates:
                defender_main.board[i][j] = SUNK
            for i, j in value.coordinates:
                defender_view.board[i][j] = SUNK
            sunken = value.name
            value.sunk = True
            clear_screen()
            print("    {}'s Board\n".format(defender.name))
            print(defender_view)
            print('\n')
            print("    {}'s Board\n".format(attacker.name))
            print(attacker_main)
            input("\nWow! Great job {}! You sunk {}'s {}! Press ENTER to continue...".format(
                attacker.name, defender.name, sunken))

def check_for_victory(defender, attacker):
    """Check to see if all of either player's ships have been sunk"""
    holder = []
    for key, value in defender.ships.items():
        holder.append(value.sunk)
    if len(holder) == 5 and all(p == True for p in holder):
        clear_screen()
        input(
            """All of {}'s ships have been sunk! {} wins!!!
            Press ENTER to quit...""".format(
            defender.name, attacker.name))
        quit()

# Actual game begins here

clear_screen()
input("Welcome to BATTLESHIP! Press ENTER to see the rules...")
clear_screen()
print("""You have five ships of varying lengths to place
anywhere on the vast open sea before you.
Choose wisely, sailors!\n
Your current fleet, along with each ship's length:\n
Aircraft Carrier, 5 spaces
Battleship, 4 spaces
Submarine, 3 spaces
Cruiser, 3 spaces
Patrol Boat, 2 spaces
""")
input("Press enter to continue...")
clear_screen()
p1_name = input("Please enter the first player's name.\n> ")
clear_screen()
p2_name = input(
    "Welcome, {}!\nPlease enter the second player's name.\n> ".format(p1_name))
p1 = Player(p1_name)
p2 = Player(p2_name)
p1_board = Board()
p2_board = Board()
p1_enemy_view = Board()
p2_enemy_view = Board()
# p1_tracker = Board()
# p2_tracker = Board()
p1_air = Ship('Aircraft Carrier', 5)
p1_ba = Ship('Battleship', 4)
p1_su = Ship('Submarine', 3)
p1_cr = Ship('Cruiser', 3)
p1_pa = Ship('Patrol Boat', 2)
p2_air = Ship('Aircraft Carrier', 5)
p2_ba = Ship('Battleship', 4)
p2_su = Ship('Submarine', 3)
p2_cr = Ship('Cruiser', 3)
p2_pa = Ship('Patrol Boat', 2)
p1.ships = {'a': p1_air, 'b': p1_ba, 'c': p1_su, 'd': p1_cr, 'e': p1_pa}
p2.ships = {'a': p2_air, 'b': p2_ba, 'c': p2_su, 'd': p2_cr, 'e': p2_pa}
clear_screen()
input("""Welcome, {}! Please make sure only
{} can see the laptop, then press ENTER...""".format(
        p2_name, p1_name)
    )
clear_screen()
choice_getter(p1_board, p1)
clear_screen()
print(p1_board)
input("""Great job, {}! Now please press ENTER and pass the
computer to {} so they can place their ships.
""".format(p1.name, p2.name))
clear_screen()
choice_getter(p2_board, p2)
clear_screen()
print(p2_board)
input("""Great job, {}! Please hit ENTER and pass the computer to
{} so they can begin their first turn.""".format(
    p2.name, p1.name)
    )
clear_screen()
game_ongoing = True
while game_ongoing:
    turn_taker(p1, p2, p1_board, p2_board, p2_enemy_view)
    check_for_victory(p2, p1)
    turn_taker(p2, p1, p2_board, p1_board, p1_enemy_view)
    check_for_victory(p2, p1)


# !/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time    : 2021/9/29
# @Author  : MashiroF
# @File    : HT_account.py
# @Software: PyCharm

## 账号管理样本
# {
#     'user':'',        # 备注,必要
#     'CK':'',          # Cookie,必要(建议全部粘贴)
#     'UA':''           # User-Agent,必要
# },

## 账号管理
# accounts = [
#     {
#         'user':'',
#         'CK':'',
#         'UA':''
#     },
#     {
#         'user':'',
#         'CK':'',
#         'UA':''
#     },
# ]
import os
cks = os.environ["HT_COOKIE"].split("&")
## 账号管理
accounts = []
for ck in cks:
    ckk=ck.split("@")
    accounts.append({'user':ckk[0],'CK':ckk[1],'UA':ckk[2]})


#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
The tornado.testing Async stuff packaged as fixtures for use with py.test

Originally from https://gist.github.com/robcowie/7843633; modified for the
instaseis server.
"""
from collections import OrderedDict
import inspect
import os
import pytest
import re
import responses
import socket
import sys

from tornado import netutil
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from tornado.testing import AsyncHTTPClient
from tornado.util import raise_exc_info

from obspy.taup import TauPyModel
from obspy import geodetics

import instaseis
from instaseis.server.app import get_application
from instaseis.database_interfaces import find_and_open_files

# Most generic way to get the data folder path.
DATA = os.path.join(os.path.dirname(os.path.abspath(
    inspect.getfile(inspect.currentframe()))), "data")

MODEL = TauPyModel("ak135")

def _assemble_url(route, **kwargs):
    """
    Helper function.
    """
    url = "/%s?" % route
    url += "&".join("%s=%s" % (key, value) for key, value in kwargs.items())
    return url

class AsyncClient(object):
    """
    A port of parts of AsyncTestCase. See tornado.testing.py:275
    """
    def __init__(self, httpserver, httpclient):
        self.__stopped = False
        self.__running = False
        self.__stop_args = None
        self.__failure = None
        self.httpserver = httpserver
        self.httpclient = httpclient

    def __del__(self):
        self.httpserver.stop()

    def _get_port(self):
        # This seems a bit fragile. How else to get the dynamic port number?
        return list(self.httpserver._sockets.values())[0].getsockname()[1]

    def fetch(self, path, use_gzip=False, **kwargs):
        port = self._get_port()
        url = u'%s://localhost:%s%s' % ('http', port, path)
        self.httpclient.fetch(url, self.stop, decompress_response=use_gzip,
                              **kwargs)
        return self.wait()

    @property
    def io_loop(self):
        # We're using a singleton ioloop throughout
        return IOLoop.instance()

    def stop(self, _arg=None, **kwargs):
        """
        Stops the `.IOLoop`, causing one pending (or future) call to `wait()`
        to return.
        """
        assert _arg is None or not kwargs
        self.__stop_args = kwargs or _arg
        if self.__running:
            self.io_loop.stop()
            self.__running = False
        self.__stopped = True

    def __rethrow(self):  # pragma: no cover
        if self.__failure is not None:
            failure = self.__failure
            self.__failure = None
            raise_exc_info(failure)

    def wait(self, condition=None, timeout=None):
        if timeout is None:
            timeout = 30

        if not self.__stopped:
            if timeout:  # pragma: no cover
                def timeout_func():
                    try:
                        raise self.failureException(
                            'Async operation timed out after %s seconds' %
                            timeout)
                    except Exception:
                        self.__failure = sys.exc_info()
                    self.stop()
                self.__timeout = self.io_loop.add_timeout(
                    self.io_loop.time() + timeout, timeout_func)
            while True:
                self.__running = True
                self.io_loop.start()
                if (self.__failure is not None or
                        condition is None or condition()):
                    break
            if self.__timeout is not None:
                self.io_loop.remove_timeout(self.__timeout)
                self.__timeout = None
        assert self.__stopped
        self.__stopped = False
        self.__rethrow()
        result = self.__stop_args
        self.__stop_args = None
        return result

def bind_unused_port():
    """
    Binds a server socket to an available port on localhost.
    Returns a tuple (socket, port).
    """
    sock = netutil.bind_sockets(None, 'localhost', family=socket.AF_INET)[0]
    port = sock.getsockname()[1]
    return sock, port

# All test databases. Fix order so tests can be executed in parallel.
DBS = OrderedDict()
DBS["db_bwd_displ_only"] = os.path.join(DATA, "100s_db_bwd_displ_only")
DBS["db_bwd_strain_only"] = os.path.join(DATA, "100s_db_bwd_strain_only")
DBS["db_fwd"] = os.path.join(DATA, "100s_db_fwd")
DBS["db_fwd_deep"] = os.path.join(DATA, "100s_db_fwd_deep")

# Add all automatically created repacked databases to the server test suite.
for name, path in pytest.config.dbs["databases"].items():
    DBS[name] = path

def event_info_mock_callback(event_id):
    """
    Mock the event info callback for the purpose of testing.
    """
    if event_id == "B071791B":
        return {
            "m_rr": -58000000000000000,
            "m_tt": 78100000000000000,
            "m_pp": -20100000000000000,
            "m_rt": -56500000000000000,
            "m_rp": 108100000000000000,
            "m_tp": 315300000000000000,
            "latitude": -3.8,
            "longitude": -104.21,
            "depth_in_m": 0,
            "origin_time": "1991-07-17T16:41:33.100000Z"}
    # Half the information is missing.
    elif event_id == "invalid_event":
        return {
            "m_rr": -58000000000000000,
            "m_pp": -20100000000000000,
            "m_rp": 108100000000000000,
            "latitude": -3.8,
            "origin_time": "1991-07-17T16:41:33.100000Z"}
    else:
        raise ValueError

def station_coordinates_mock_callback(networks, stations):
    """
    Mock station coordinates callback for the purpose of testing.

    Return a single station for networks=["IU"] and stations=["ANMO"],
    two stations for networks=["IU", "B*"] and stations=["ANT*", "ANM?"] and no
    stations for all other combinations.
    """
    if networks == ["IU"] and stations == ["ANMO"]:
        return [{
            "latitude": 34.94591,
            "longitude": -106.4572,
            "network": "IU",
            "station": "ANMO"}]
    elif networks == ["IU", "B*"] and stations == ["ANT*", "ANM?"]:
        return [{
            "latitude": 39.868,
            "longitude": 32.7934,
            "network": "IU",
            "station": "ANTO"
         }, {
            "latitude": 34.94591,
            "longitude": -106.4572,
            "network": "IU",
            "station": "ANMO"}]
    # Invalid coordinates!
    elif networks == ["XX"] and stations == ["DUMMY"]:
        return [{
            "latitude": 3E9,
            "longitude": -106.4572,
            "network": "XX",
            "station": "DUMMY"}]
    else:
        return []

def get_travel_time(sourcelatitude, sourcelongitude, sourcedepthinmeters,
                    receiverlatitude, receiverlongitude,
                    receiverdepthinmeters, phase_name, db_info):
    """
    Fully working travel time callback implementation.
    """
    if receiverdepthinmeters:
        raise ValueError("This travel time implementation cannot calculate "
                         "buried receivers.")

    great_circle_distance = geodetics.locations2degrees(
        sourcelatitude, sourcelongitude, receiverlatitude, receiverlongitude)

    try:
        tts = MODEL.get_travel_times(
            source_depth_in_km=sourcedepthinmeters / 1000.0,
            distance_in_degree=great_circle_distance,
            phase_list=[phase_name])
    except Exception as e:
        raise ValueError(str(e))

    if not tts:
        return None

    # For any phase, return the first time.
    return tts[0].time

def create_async_client(path, station_coordinates_callback=None,
                        event_info_callback=None,
                        travel_time_callback=None):
    application = get_application()
    application.db = find_and_open_files(path=path)
    application.station_coordinates_callback = station_coordinates_callback
    application.event_info_callback = event_info_callback
    application.travel_time_callback = travel_time_callback
    application.max_size_of_finite_sources = 1000
    # Build server as in testing:311
    sock, port = bind_unused_port()
    server = HTTPServer(application, io_loop=IOLoop.instance())
    server.add_sockets([sock])
    client = AsyncClient(server, AsyncHTTPClient())
    client.application = application
    client.filepath = path
    client.port = port
    # Flag to help deal with forward/backwards databases.
    b = os.path.basename(path)
    if "bwd" in b or "horizontal_only" in b or "vertical_only" in b:
        client.is_reciprocal = True
        client.source_depth = 0.0
    else:
        client.is_reciprocal = False
        client.source_depth = application.db.info.source_depth * 1000
    client.info = application.db.info
    return client

@pytest.fixture(params=list(DBS.values()))
def all_clients(request):
    """
    Fixture returning all clients!
    """
    return create_async_client(request.param,
                               station_coordinates_callback=None)

@pytest.fixture(params=[_i for _i in list(DBS.values()) if (
        "db_bwd" in _i and
        "horizontal_only" not in _i and
        "vertical_only" not in _i)])
def all_greens_clients(request):
    """
    Fixture returning all clients compatible with Green's functions!
    """
    return create_async_client(request.param,
                               station_coordinates_callback=None)

@pytest.fixture(params=[_i for _i in list(DBS.values()) if "db_bwd" in _i])
def reciprocal_clients(request):
    """
    Fixture returning all reciprocal clients!
    """
    return create_async_client(request.param,
                               station_coordinates_callback=None)

@pytest.fixture(params=list(DBS.values()))
def all_clients_station_coordinates_callback(request):
    """
    Fixture returning all with a station coordinates callback.
    """
    return create_async_client(
        request.param,
        station_coordinates_callback=station_coordinates_mock_callback)

@pytest.fixture(params=list(DBS.values()))
def all_clients_event_callback(request):
    """
    Fixture returning all with a event info callback.
    """
    return create_async_client(
        request.param,
        event_info_callback=event_info_mock_callback)

@pytest.fixture(params=list(DBS.values()))
def all_clients_ttimes_callback(request):
    """
    Fixture returning all clients with a travel time callback.
    """
    return create_async_client(
        request.param,
        travel_time_callback=get_travel_time)

@pytest.fixture(params=[_i for _i in list(DBS.values()) if (
        "db_bwd" in _i and
        "horizontal_only" not in _i and
        "vertical_only" not in _i)])
def all_greens_clients_ttimes_callback(request):
    """
    Fixture returning all clients compatible with Green's functions!
    """
    return create_async_client(
        request.param,
        travel_time_callback=get_travel_time)

@pytest.fixture(params=[_i for _i in list(DBS.values()) if
                        ("db_bwd" in _i or "_only_" in _i)])
def reciprocal_clients_all_callbacks(request):
    """
    Fixture returning reciprocal clients with all callbacks.
    """
    return create_async_client(
        request.param,
        station_coordinates_callback=station_coordinates_mock_callback,
        event_info_callback=event_info_mock_callback,
        travel_time_callback=get_travel_time)

@pytest.fixture(params=list(DBS.values()))
def all_clients_all_callbacks(request):
    """
    Fixture returning all clients with all callbacks.
    """
    return create_async_client(
        request.param,
        station_coordinates_callback=station_coordinates_mock_callback,
        event_info_callback=event_info_mock_callback,
        travel_time_callback=get_travel_time)

def _add_callback(client):
    def request_callback(request):
        req = client.fetch(request.path_url)
        return (req.code, req.headers, req.body)

    pattern = re.compile(r"http://localhost.*")
    responses.add_callback(
        responses.GET, pattern,
        callback=request_callback,
        content_type="application/octet_stream"
    )

@pytest.fixture(params=list(DBS.values()))
@responses.activate
def all_remote_dbs(request):
    client = create_async_client(request.param, None)

    _add_callback(client)

    db = instaseis.open_db("http://localhost:%i" % client.port)
    db._client = client
    return db


import os
from unittest import TestCase
from myuw.dao.affiliation_data import (_load_data_from_file,
                                       get_data_for_affiliations)
from myuw.dao.exceptions import InvalidAffiliationDataFile
from myuw.models.res_category_link import ResCategoryLink

def _make_path(file_name):
    return os.path.join('test', file_name)

class TestLoadAffiliationData(TestCase):
    def test_load_bad_file_headers(self):
        with self.assertRaises(InvalidAffiliationDataFile):
            _load_data_from_file(_make_path('missing_headers'))

    def test_load_bad_file_pce(self):
        with self.assertRaises(InvalidAffiliationDataFile):
            _load_data_from_file(_make_path('bad_pce_status'))

    def test_load_valid_file(self):
        data = _load_data_from_file(_make_path('basic_valid'))
        self.assertEquals(len(data), 7)

        self.assertEquals(data[0]['campus'], 'seattle')
        self.assertEquals(data[1]['campus'], 'seattle')
        self.assertEquals(data[2]['campus'], 'bothell')
        self.assertEquals(data[3]['campus'], None)
        self.assertEquals(data[4]['campus'], None)

        self.assertEquals(data[0]['affiliation'], 'undergrad')
        self.assertEquals(data[1]['affiliation'], 'grad')
        self.assertEquals(data[2]['affiliation'], 'grad')
        self.assertEquals(data[3]['affiliation'], None)
        self.assertEquals(data[4]['affiliation'], None)

        self.assertFalse(data[0]['pce'])
        self.assertTrue(data[1]['pce'])
        self.assertTrue(data[2]['pce'] is None)
        self.assertTrue(data[3]['pce'] is None)
        self.assertTrue(data[4]['pce'] is None)

    def test_data_from_file(self):
        links = get_data_for_affiliations(file=_make_path('basic_valid'),
                                          affiliations={'seattle': True,
                                                        'tacoma': False,
                                                        'undergrad': True,
                                                        'grad': False,
                                                        'pce': False,
                                                        })

        self.assertEquals(len(links), 3)
        self.assertEquals(links[0]['extra'], 'ok')
        self.assertEquals(links[1]['extra'], 'ok4')
        self.assertEquals(links[2]['extra'], 'ok5')

    def test_data_from_model(self):
        ResCategoryLink.objects.all().delete()
        links = get_data_for_affiliations(model=ResCategoryLink,
                                          affiliations={'seattle': True,
                                                        'undergrad': True,
                                                        'grad': False,
                                                        'pce': False,
                                                        })

        self.assertEquals(len(links), 0)

        ResCategoryLink.objects.create(title="link1",
                                       url="http://example.com?q=0")
        ResCategoryLink.objects.create(title="link2",
                                       url="http://example.com?q=1",
                                       affiliation='undergrad',
                                       campus='seattle',
                                       pce=True)
        ResCategoryLink.objects.create(title="link3",
                                       url="http://example.com?q=2",
                                       affiliation='undergrad',
                                       campus='seattle',
                                       pce=False)

        links = get_data_for_affiliations(model=ResCategoryLink,
                                          affiliations={'seattle': True,
                                                        'undergrad': True,
                                                        'grad': False,
                                                        'pce': False,
                                                        })
        self.assertEquals(len(links), 2)
        self.assertEqual(links[0].title, 'link1')
        self.assertEqual(links[0].url, 'http://example.com?q=0')
        self.assertEqual(links[1].title, 'link3')
        self.assertEqual(links[1].url, 'http://example.com?q=2')

    def test_unique_data(self):
        ResCategoryLink.objects.all().delete()
        ResCategoryLink.objects.create(title="link1",
                                       url="http://example.com?q=0")
        ResCategoryLink.objects.create(title="link2",
                                       url="http://example.com?q=0")
        ResCategoryLink.objects.create(title="link3",
                                       url="http://example.com?q=0")
        ResCategoryLink.objects.create(title="link4",
                                       url="http://example.com?q=0")

        links = get_data_for_affiliations(model=ResCategoryLink)
        self.assertEquals(len(links), 4)

        links = get_data_for_affiliations(model=ResCategoryLink,
                                          unique=lambda x: x.url)
        self.assertEquals(len(links), 1)
        self.assertEquals(links[0].title, "link1")


import string
# Day8 폴더 안에 있어야 실행 된다!

# 시저 암호를 구현하시오

# 평문이 들어있는 파일을 읽고
# 위의 암호표를 참고하여 변환한 후
# 평문 아래에 변환된 내용을 적으시오
# 모두 소문자로만 한정한다
# Ex) i am a boy
# -> o dp d erb

f = open("./Day8 예외 처리와 파일/3.txt", 'r')
data = f.read()
f.close()

# 소문자만 받는 시저 암호
def solution(s, n):
    s = list(s)
    for i in range(len(s)):
        if s[i].islower():
            s[i] = chr((ord(s[i]))+3)
        else:
            s[i] = " "

    return "".join(s)

c = solution(data, len(data))

# writedata.py
f = open("./Day8 예외 처리와 파일/3의 결과.txt", 'w')

f.write(c)
f.close()

Day8 예외 처리와 파일/3 시저암호.py


import pygame
import os
import Objects
from ScreenEngine import GameSurface, ProgressBar, InfoWindow, HelpWindow, ScreenHandle, MiniMap
import Logic
import Service
from Settings import Settings

SCREEN_DIM = (800, 600)
KEYBOARD_CONTROL = True

if not KEYBOARD_CONTROL:
    import numpy as np

class Game:
    def __init__(self):
        pygame.init()
        self.gameDisplay = pygame.display.set_mode(SCREEN_DIM)
        pygame.display.set_caption("MyRPG")

        if not KEYBOARD_CONTROL:
            answer = np.zeros(4, dtype=float)

        self.settings = Settings()
        self.engine = Logic.GameEngine()
        self.drawer = None
        self.iteration = 0
        self.size = 60

    def start(self):
        self.create_game(self.size, True)
        self.check_events()
        pygame.display.quit()
        pygame.quit()
        exit(0)

    def create_game(self, sprite_size, is_new):
        if is_new:
            self.engine = Logic.GameEngine()
            self.engine.hero = Objects.Hero(self.settings.base_stats, Service.create_sprite(
                os.path.join("texture", "Hero.png"), sprite_size))
            Service.service_init(sprite_size)
            Service.reload_game(self.engine, self.engine.hero)
            self.set_chain()
        else:
            self.engine.sprite_size = sprite_size
            self.engine.hero.sprite = Service.create_sprite(
                os.path.join("texture", "Hero.png"), sprite_size)
            Service.service_init(sprite_size, False)

        Logic.GameEngine.sprite_size = sprite_size

        self.drawer.connect_engine(self.engine)

        self.iteration = 0

    def set_chain(self):
        self.drawer = ScreenHandle((0, 0))
        self.drawer = HelpWindow((700, 500), pygame.SRCALPHA, (0, 0), self.drawer)
        self.drawer = MiniMap((164, 164), pygame.SRCALPHA, (20, 20), self.drawer)
        self.drawer = InfoWindow((160, 600), (476, 0), self.drawer)
        self.drawer = ProgressBar((640, 120), (640, 0), self.drawer)
        self.drawer = GameSurface((640, 480), pygame.SRCALPHA, (0, 480), self.drawer)

    def check_events(self):
        while self.engine.working:
            if self.engine.hero.dead:
                self.engine.hero.dead = not self.engine.hero.dead
                self.create_game(self.size, True)
                self.engine.notify("Hero dead. Game restarted")

            if KEYBOARD_CONTROL:
                for event in pygame.event.get():
                    if event.type == pygame.QUIT:
                        self.engine.working = False
                    if event.type == pygame.KEYDOWN:
                        if event.key == pygame.K_h:
                            self.engine.show_help = not self.engine.show_help
                        if event.key == pygame.K_KP_PLUS:
                            self.engine.zoom_in()
                            self.size = self.engine.sprite_size
                            self.create_game(self.size, False)
                        if event.key == pygame.K_KP_MINUS:
                            self.engine.zoom_out()
                            self.size = self.engine.sprite_size
                            self.create_game(self.size, False)
                        if event.key == pygame.K_r:
                            self.create_game(self.size, True)
                        if event.key == pygame.K_m:
                            self.engine.show_minimap = not self.engine.show_minimap
                        if event.key == pygame.K_ESCAPE:
                            self.engine.working = False
                        if self.engine.game_process:
                            if event.key == pygame.K_UP:
                                self.engine.move_up()
                                self.iteration += 1
                            elif event.key == pygame.K_DOWN:
                                self.engine.move_down()
                                self.iteration += 1
                            elif event.key == pygame.K_LEFT:
                                self.engine.move_left()
                                self.iteration += 1
                            elif event.key == pygame.K_RIGHT:
                                self.engine.move_right()
                                self.iteration += 1
                        else:
                            if event.key == pygame.K_RETURN:
                                self.create_game()
            else:
                for event in pygame.event.get():
                    if event.type == pygame.QUIT:
                        self.engine.working = False
                if self.engine.game_process:
                    actions = [
                        self.engine.move_right,
                        self.engine.move_left,
                        self.engine.move_up,
                        self.engine.move_down,
                    ]
                    answer = np.random.randint(0, 100, 4)
                    prev_score = self.engine.score
                    move = actions[np.argmax(answer)]()
                    state = pygame.surfarray.array3d(self.gameDisplay)
                    reward = self.engine.score - prev_score
                    print(reward)
                else:
                    self.create_game()

            self.gameDisplay.blit(self.drawer, (0, 0))
            self.drawer.draw(self.gameDisplay)

            pygame.display.update()

if __name__ == "__main__":
    game = Game()
    game.start()


from django import forms
from yt_app.models import Tournament, Place, Game, Team, Match
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError

class AddTournamentForm(forms.Form):
    name = forms.CharField()
    description = forms.CharField()
    place = forms.ModelChoiceField(queryset=Place.objects.all())
    game = forms.ModelChoiceField(queryset=Game.objects.all())

class AddPlaceForm(forms.Form):
    name = forms.CharField()
    description = forms.CharField()
    address = forms.CharField()

class AddGameForm(forms.Form):
    game_type = forms.ChoiceField(choices=Game.G_TYPES)
    name = forms.CharField()
    description = forms.CharField()

class AddTeamForm(forms.Form):
    name = forms.CharField()
    tournaments = forms.ModelChoiceField(queryset=Tournament.objects.all())
    players = forms.ModelMultipleChoiceField(queryset=User.objects.all())

class AddMatchForm(forms.Form):
    name = forms.CharField()
    team1 = forms.ModelChoiceField(queryset=Team.objects.all())
    team2 = forms.ModelChoiceField(queryset=Team.objects.all())
    tournament = forms.ModelChoiceField(queryset=Tournament.objects.all())

    def clean(self):
        cleaned_data = super().clean()

        team1 = cleaned_data.get('team1')
        team2 = cleaned_data.get('team2')

        if team1 == team2:
            raise forms.ValidationError('Teams have to be different')

class AddDuelForm(forms.Form):
    match_field = forms.ModelChoiceField(queryset=Match.objects.all(), label='Match')

class UpdateTeamForm(forms.Form):
    team = forms.ModelChoiceField(queryset=Team.objects.all())
    tournaments_ch= forms.ModelMultipleChoiceField(queryset=Tournament.objects.all(), label='Change tournaments')
    players_ch = forms.ModelMultipleChoiceField(queryset=User.objects.all(), label='Change players')


# -*- coding:utf-8 -*-
"""
author:Bonnieliuliu
email:fangyuanliu@pku.edu.cn

file: IsSubsequence.py
time: 2018/8/19 21:51
"""

class Solution:
    def isSubsequence(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: bool
        """
        if len(s) <= 0:
            return True
        if len(t) <= 0:
            return False
        i = 0
        j = 0
        while i < len(s) and j < len(t):
            if s[i] == t[j]:
                i += 1
                j += 1
            else:
                j += 1
        if i == len(s) and s[i - 1] == t[j - 1]:
            return True
        else:
            return False


'''
import random
r = int(random.randrange(1, 10000000000))
t = float(random.randrange(1, 10))
print(r)
print(t)
'''

#txt = "The best things in life are free!"
#print ("Tha" in txt)

import random
rand = (random.randrange(1, 10))
txt = "you'r random number is {}"
print (txt.format(rand))
finish = ("you win", "you lose", "try again")

c = 5
if rand > c:
  print(finish[0])
if rand < c:
  print(finish[1])
if rand == c:
  print(finish[2])


# re package to use regular expressions
import re
# pypdf to extract data from pdf
import pypdf
# tempfile to create temporary files
import tempfile

incidents = []
fp = tempfile.TemporaryFile()

# extractincidents function to extract incidents
def extractincidents(data):
	#print("***Extraction Started***")
	fp.write(data)
	fp.seek(0)
	reader = pypdf.PdfReader(fp)
	page = len(reader.pages)

	for p in range(0, page):
		temp = []
		page_data = reader.pages[p].extract_text()
		line = ""
		dualline = 0
		for i in range(0, len(page_data)):
			if (page_data[i] == '\n'):

				if(line == 'Date / Time Incident Number Location Nature Incident ORI'):
					pass
				else:
					#print(line)
					s1 = ""
					ori = ""
					word_arr = line.split(" ")
					#print(word_arr[0])
					#print(word_arr[1])
					#print(word_arr[2])
					for i in range(3,len(word_arr)):
						if (word_arr[i] == "OK0140200" or word_arr[i] == "EMSSTAT" or word_arr[i] == "14005" or word_arr[i]=="14009"):
							dualline = 0
							break
						else:
							dualline = 1

					if dualline == 0:
						for i in range(3,len(word_arr)):
							if (word_arr[i] == "OK0140200" or word_arr[i] == "EMSSTAT" or word_arr[i] == "14005" or word_arr[i]=="14009"):
								#print(word_arr[i])
								ori = word_arr[i]

							else:
								s1 += word_arr[i] + " "

						pattern = r"\b(?:[A-Z][a-z]+|911 Call Nature Unknown|MVA With Injuries|MVA Non Injury|COP.*)\b"

						match = re.findall(pattern,s1)

						s2 = ""

						if len(match) == 0 and len(s1.strip()) == 0:
							s2 = "Nan"
							s1 = "Nan"
						elif len(match) == 0:
							s2 = "Nan"
						elif len(s1.strip()) == 0:
							s1 = "Nan"
						else:
							if match[0] == "911 Call Nature Unknown" or match[0] =="MVA With Injuries" or match[0] == "MVA Non Injury":
								s2 = match[0]
							else:
								s2 = s1.split(match[0],1)[1]

								if s2.strip().startswith("/"):
									s2 = match[0] + s2.strip()
								else:
									s2 = match[0] + " " + s2.strip()

						#print(s2)
						#print('subtract this :')
						#print(s1,'--',s2)
						if s1 == "Nan":
							lock = "Nan"
						else:
							lock = s1.replace(s2,"")
						#print(lock)
						temp.append(word_arr[0]+" "+word_arr[1])
						temp.append(word_arr[2])
						temp.append(lock)
						temp.append(s2)
						temp.append(ori)
						incidents.append([temp])

					if dualline == 1:
						dualline = 0
						continue

				temp = []
				line = str()
			else:
				line += page_data[i]

	return incidents


# Importing dependencies
import pandas as pd
import datetime
from pathlib import Path

class DF_Processor:
    """
    This class reads, processes and returns both regional and non-regional CSVs as DataFrames from the Data directory.
    The __init__ (constructor) method sets both the regional and non-regional CSV titles as class variables.
    The get_dfs method takes in the is_regional boolean flag and outputs a list of all of the requested DataFrames.
    The process_dfs method takes care of all the necessary DataFrame processing we need to get our data in the right form.
    The get_regional_data method returns a list of the regional DataFrames.
    And the get_non_regional_data returns a list of the non-regional DataFrames.
    """

    # Constructor
    def __init__(self):
        # List of non-regional csv titles
        self.non_regional_titles = ['National','Energy','Food', 'National-Less-Food-Energy']
        # List of regional csv titles
        self.regional_titles = ['Midwest', 'Northeast', 'South', 'West']

    # Method to get dataframes
    def get_dfs(self, is_regional):
        # Empty list to hold DataFrames
        dataframes = []

        # Setting titles list
        titles = self.regional_titles if is_regional else self.non_regional_titles

        # Looping over csv titles list
        for title in titles:
            # Columns to drop
            columns_to_drop = ['HALF1','HALF2']

            # If the regional flag is set
            if is_regional:
                # Append the Annual column
                columns_to_drop.append('Annual')

            # Saving the csv (by title) as DataFrame, dropping un-needed comments, and reshaping using melt
            df = pd.read_csv(Path(f'./Data/{title}.csv')).drop(columns=columns_to_drop).melt(id_vars=['Year'], var_name='Month', value_name='Price')

            # Appending dataframe to dataframes list
            dataframes.append(df)

        # Returning all dataframes
        return dataframes

    # Method to data pre-process dataframes
    def process_dfs(self, is_regional):
        # Empty list to hold processed DataFrames
        processed_dataframes = []
        # Dictionary of months and thier numeric values
        months = {'Jan':1,'Feb':2,'Mar':3,'Apr':4,'May':5,'Jun':6,'Jul':7,'Aug':8,'Sep':9,'Oct':10,'Nov':11,'Dec':12}
        # Get and loop over DataFrames
        for df in self.get_dfs(is_regional):
            # Creating Day column and setting values to 1
            df['Day']=1
            # Mapping month from string to int
            df['Month'] = df['Month'].map(months)

            # Creating date column
            df['Date']=pd.to_datetime(dict(year=df.Year, month=df.Month, day=df.Day))
            # Sorting Date values
            df = df.sort_values('Date')
            # Making index Date
            df.index = df['Date']

            # Dropping Year, Month, Day, Date columns
            df = df.drop(columns=['Year','Month','Day','Date'])
            # Dropping NaN values
            df = df.dropna()

            # Adding current DataFrame to processed_dataframes list
            processed_dataframes.append(df)
        #Returning all of the processed dataframes
        return processed_dataframes

    # Method to get regional DataFrames
    def get_regional_data(self):
        # Return the processed regional DataFrames
        return self.process_dfs(True)

    # Method to get non-regional DataFrames
    def get_non_regional_data(self):
        # Return the processed non-regional DataFrames
        return self.process_dfs(False)