# -*- coding: utf-8 -*-

import xlrd
import csv
import base64

from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError

class ResPartnerImportWizard(models.TransientModel):
    _name = 'res.partner.import.wizard'
    _description = 'Res Partner Import Wizard'

    # dbo entity
    dbo_entity_file = fields.Binary("DBO Entity File", required=True)
    dbo_entity_file_name = fields.Char("DBO Entity File Name")
    # dbo_entity_address
    dbo_entity_address_file = fields.Binary("DBO Entity Address File")
    dbo_entity_address_file_name = fields.Char("DBO Entity Address File Name")
    # dbo entity contact
    dbo_entity_contact_file = fields.Binary("DBO Entity Contact File")
    dbo_entity_contact_file_name = fields.Char("DBO Entity Contact File Name")

    def _read_xlsx_file(self, file, cell_data, required_columns, file_name, partner_check):
        """
        Read .xlsx type files
        """
        vals = []
        counter = 1
        skipped_line_no = []
        try:
            workbook = xlrd.open_workbook(file_contents=base64.decodebytes(file))
            sheet = workbook.sheet_by_index(0)

            for row in range(sheet.nrows):
                if row > 1:  # skip header lines
                    try:
                        data = {}
                        for rec in cell_data:
                            if sheet.cell(row, rec).value != '':
                                data.update({cell_data[rec]: sheet.cell(row, rec).value})
                                # check the partner exist otherwise skip line
                                if cell_data[rec] == 'entity_id' and not self.env['res.partner'].search([('entity_id', '=', sheet.cell(row, rec).value)]) and partner_check:
                                    skipped_line_no.append({
                                        'line': counter,
                                        'entity_file': file_name,
                                        'reason': 'Partner not found for the entity id - %s' % str(sheet.cell(row, rec).value)
                                    })
                            # check the cell is required otherwise skip line
                            elif cell_data[rec] in required_columns:
                                skipped_line_no.append({
                                    'line': counter,
                                    'entity_file': file_name,
                                    'reason': '%s column not found' % cell_data[rec]
                                })
                        vals.append(data)
                    except Exception as e:
                        # skip line if an error occurred
                        skipped_line_no.append({
                            'line': counter,
                            'entity_file': file_name,
                            'reason': 'Value is not valid - %s' % str(e)
                        })
                counter += 1

        except Exception:
            raise UserError(_("Invalid xlsx file. Please check the file that you are trying to import!"))

        return vals, skipped_line_no

    def _read_csv_file(self, file, cell_data, required_columns, file_name, partner_check):
        """
        Read .csv type files
        """
        vals = []
        counter = 1
        skipped_line_no = []
        try:
            file = str(base64.decodebytes(file).decode('utf-8'))
            csvreader = csv.reader(file.splitlines())

            i = 0
            for row in csvreader:
                if i > 1:  # skip header lines
                    try:
                        data = {}
                        for rec in cell_data:
                            if row[rec] != '':
                                data.update({cell_data[rec]: row[rec]})
                                # check the partner exist otherwise skip line
                                if cell_data[rec] == 'entity_id' and not self.env['res.partner'].search([('entity_id', '=', row[rec])]) and partner_check:
                                    skipped_line_no.append({
                                        'line': counter,
                                        'entity_file': file_name,
                                        'reason': 'Partner not found for the entity id - %s' % str(row[rec])
                                    })
                            # check the cell is required otherwise skip line
                            elif cell_data[rec] in required_columns:
                                skipped_line_no.append({
                                    'line': counter,
                                    'entity_file': file_name,
                                    'reason': '%s column not found' % cell_data[rec]
                                })
                        vals.append(data)
                    except Exception as e:
                        # skip line if an error occurred
                        skipped_line_no.append({
                            'line': counter,
                            'entity_file': file_name,
                            'reason': 'Value is not valid - %s' % str(e)
                        })
                counter += 1
                i += 1
        except Exception:
            raise UserError(_("Invalid csv file. Please check the file that you are trying to import!"))

        return vals, skipped_line_no

    def _process_entity_data(self, data):
        """
        Create or update partner for dbo entity data
        """
        for rec in [x for x in data if ('name' in x and 'entity_id' in x)]:
            # check already assigned partner
            partner_id = self.env['res.partner'].search([('entity_id', '=', int(rec['entity_id']))], limit=1)
            vals = {
                'entity_id': rec['entity_id'],
                'dealer_id': rec.get('dealer_id', False),
                'company': rec.get('company', False),
                'entity_type_id': rec.get('entity_type_id', False),
                'entity_category_id': rec.get('entity_category_id', False),
                'entity_creator_id': rec.get('entity_creator_id', False),
                'entity_updater_id': rec.get('entity_updater_id', False),
                'abc_cat_id': rec.get('abc_cat_id', False),
                'bus_cat_id': rec.get('bus_cat_id', False),
                'notes': rec.get('notes', False),
                'date_added': rec.get('date_added', False),
                'date_modified': rec.get('date_modified', False),
                'name': rec['name'],
                'switchboard': rec.get('switchboard', False),
                'fax': rec.get('fax', False),
                'url': rec.get('url', False),
                'email': rec.get('email', False),
                'vat': rec.get('vat', False),
                'vat_except_num': rec.get('vat_except_num', False),
                'accept_back_orders': rec.get('accept_back_orders', False),
                'menthod_of_contact': rec.get('menthod_of_contact', False),
                'catdesc': rec.get('catdesc', False),
                'website': rec.get('website', False),
                'comptel': rec.get('comptel', False),
                'next_call_date': rec.get('next_call_date', False),
                'account_type_id': rec.get('account_type_id', False),
                'date_updated': rec.get('date_updated', False),
                'temp_id': rec.get('temp_id', False),
                'compregnum': rec.get('compregnum', False),
                'account_num': rec.get('account_num', False),
                'modified_by': rec.get('modified_by', False),
                'account_supplier_id': rec.get('account_supplier_id', False),
                'account_customer_id': rec.get('account_customer_id', False),
                'is_birthday_supplier': rec.get('is_birthday_supplier', False),
                'is_birthday_courier': rec.get('is_birthday_courier', False),
                'is_anniversary_courier': rec.get('is_anniversary_courier', False),
                'is_anniversary_supplier': rec.get('is_anniversary_supplier', False),
                'is_account_supplier': rec.get('is_account_supplier', False),
                'is_supplier': rec.get('is_supplier', False),
                'invoice_to': rec.get('invoice_to', False),
                'currency': rec.get('currency', False),
                'credit_limit': rec.get('credit_limit', False),
                'payment_terms': rec.get('payment_terms', False),
                'sdl_no': rec.get('sdl_no', False),
                'sic_code': rec.get('sic_code', False),
                'ofo_no': rec.get('ofo_no', False),
                'markup': rec.get('markup', False),
                'client_rating': rec.get('client_rating', False),
                'manual_rating': rec.get('manual_rating', False),
                'sales_cons_id': rec.get('sales_cons_id', False),
                'alternate_company_id': rec.get('comments', False),
                'comments': rec.get('comments', False),
                'card_type_id': rec.get('card_type_id', False),
                'credit_card_name': rec.get('credit_card_name', False),
                'credit_card_number': rec.get('credit_card_number', False),
                'exp_month': rec.get('exp_month', False),
                'exp_year': rec.get('exp_year', False),
                'bank_recon_notes': rec.get('bank_recon_notes', False),
                'acc_stat_id': rec.get('acc_stat_id', False),
                'avg_payment_time': rec.get('avg_payment_time', False),
                'vendor_number': rec.get('vendor_number', False),
                'source_id': rec.get('source_id', False),
                'pricelistID': rec.get('pricelistID', False),
                'bank_branch_name': rec.get('bank_branch_name', False),
                'bank_branch_code': rec.get('bank_branch_code', False),
                'debit_order': rec.get('debit_order', False),
                'ref_no': rec.get('ref_no', False),
                'tax_type_id': rec.get('tax_type_id', False),
                'industry_id': rec.get('industry_id', False),
                'entity_subtype_id': rec.get('entity_subtype_id', False),
                'temp_id_varchar': rec.get('temp_id_varchar', False),
                'is_vat_exempt': rec.get('is_vat_exempt', False),
                'in_active': rec.get('in_active', False),
                'cnt_order_number': rec.get('cnt_order_number', False),
                'cnt_id_number': rec.get('cnt_id_number', False),
                'cnt_damage_waiver': rec.get('cnt_damage_waiver', False),
                'cnt_sites': rec.get('cnt_sites', False),
            }
            # update partner if exist
            if partner_id:
                partner_id.update(vals)
            else:  # create partner if not exist
                partner_id.create(vals)

    def _process_entity_address_data(self, data):
        """
        Create or update partner for dbo entity address data
        """
        for rec in [x for x in data if ('entity_address_id' in x and 'entity_id' in x and 'address_type' in x)]:
            res_partner_obj = self.env['res.partner']
            # check already assigned partner_id
            partner_id = res_partner_obj.search([('entity_id', '=', int(rec['entity_id']))], limit=1)
            if bool(partner_id):
                # update address_type
                address_type = 'postal' if (rec['address_type'] == 'Postal Address') else 'physical'
                # check address partner already exist
                entity_address_id = res_partner_obj.search([('entity_id', '=', int(rec['entity_address_id'])), ('type', '=', 'other')])
                # prepare country
                country_id = False
                if 'country' in rec:
                    country_id = self.env['res.country'].search([('name', '=', rec['country'])], limit=1).id
                # prepare state
                state_id = False
                if 'state' in rec:
                    state_id = self.env['res.country.state'].search([('name', '=', rec['state'])], limit=1).id

                # prepare values
                vals = {
                    'entity_id': int(rec['entity_address_id']),
                    'type': 'other',
                    'entity_address_type': address_type,
                    'street': rec['address_1'],
                    'address_2': rec.get('address_2', False),
                    'address_3': rec.get('address_3', False),
                    'city': rec.get('city', False),
                    'region': rec.get('region', False),
                    'code': rec.get('code', False),
                    'country_id': country_id,
                    'state_id': state_id,
                    'temp_id': rec.get('temp_id', False),
                    'is_default': True if rec.get('is_default', False) == 1 else False,
                    'address_4': rec.get('address_4', False),
                }
                # update address partner if exist
                if entity_address_id:
                    entity_address_id.update(vals)
                else:  # create address partner if not exist
                    partner_id.update({'child_ids': [(0, 0, vals)]})

    def _process_entity_contact_data(self, data):
        """
        Create or update partner for dbo entity contact data
        """
        for rec in [x for x in data if ('entity_address_id' in x and 'entity_id' in x)]:
            res_partner_obj = self.env['res.partner']
            # check already assigned partner
            partner_id = res_partner_obj.search([('entity_id', '=', int(rec['entity_id']))], limit=1)
            if bool(partner_id):
                # check entity contact
                entity_contact_id = res_partner_obj.search([('entity_id', '=', int(rec['entity_address_id'])), ('type', '=', 'contact')])
                # prepare title
                title = False
                if 'title' in rec:
                    title = self.env['res.partner.title'].search([('name', '=', rec['title'])], limit=1)
                    if not title:
                        title = self.env['res.partner.title'].create({'name': rec['title']})
                # prepare country
                country_id = False
                if 'country' in rec:
                    country_id = self.env['res.country'].search([('name', '=', rec['country'])], limit=1).id
                # prepare state
                state_id = False
                if 'state' in rec:
                    state_id = self.env['res.country.state'].search([('name', '=', rec['state'])], limit=1).id
                # prepare values for update or create record
                vals = {
                    'type': 'contact',
                    'entity_id': rec['entity_address_id'],
                    'name': ' '.join([rec.get('initials', ''), rec.get('first_name', ''), rec.get('surname', '')]),
                    'title': title.id if title else False,
                    'entity_type_id': rec.get('entity_type_id', False),
                    'entity_category_id': rec.get('entity_category_id', False),
                    'alternate_contact_id': rec.get('alternate_contact_id', False),
                    'entity_contact_updater_id': rec.get('entity_contact_updater_id', False),
                    'entity_contact_creator_id': rec.get('entity_contact_creator_id', False),
                    'physical_addr_id': rec.get('physical_addr_id', False),
                    'postal_addr_id': rec.get('postal_addr_id', False),
                    'cont_type_id': rec.get('cont_type_id', False),
                    'position_id': rec.get('position_id', False),
                    'sales_cons_id': rec.get('sales_cons_id', False),
                    'bus_cat_id': rec.get('buscatid', False),
                    'abc_cat_id': rec.get('abc_catid', False),
                    'is_default': rec.get('is_default', False),
                    'company': rec.get('company', False),
                    'phone': rec.get('phone', False),
                    'phone2': rec.get('phone2', False),
                    'phone3': rec.get('phone3', False),
                    'home_phone': rec.get('home_phone', False),
                    'mobile': rec.get('mobile', False),
                    'fax': rec.get('fax', False),
                    'email': rec.get('email', False),
                    'ext': rec.get('ext', False),
                    'department': rec.get('department', False),
                    'spouse': rec.get('spouse', False),
                    'asst_title': rec.get('asst_title', False),
                    'asst_name': rec.get('asst_name', False),
                    'asst_phone': rec.get('asst_phone', False),
                    'asst_ext': rec.get('asst_ext', False),
                    'hobbies': rec.get('hobbies', False),
                    'notes': rec.get('notes', False),
                    'street': rec.get('address1', False),
                    'address_2': rec.get('address2', False),
                    'address_3': rec.get('address3', False),
                    'city': rec.get('city', False),
                    'state_id': state_id,
                    'code': rec.get('code', False),
                    'region': rec.get('region', False),
                    'country_id': country_id,
                    'poaddress1': rec.get('poaddress1', False),
                    'poaddress2': rec.get('poaddress2', False),
                    'poaddress3': rec.get('poaddress3', False),
                    'pocity': rec.get('pocity', False),
                    'postate': rec.get('postate', False),
                    'pocode': rec.get('pocode', False),
                    'poregion': rec.get('poregion', False),
                    'pocountry': rec.get('pocountry', False),
                    'birth_date': rec.get('birth_date', False),
                    'path': rec.get('path', False),
                    'province': rec.get('province', False),
                    'is_supplier': rec.get('is_supplier', False),
                    'send_email': rec.get('send_email', False),
                    'send_sms': rec.get('send_sms', False),
                    'date_updated': rec.get('date_updated', False),
                    'account_num': rec.get('account_num', False),
                    'entity_htype': rec.get('entity_htype', False),
                    'date_added': rec.get('date_added', False),
                    'date_modified': rec.get('date_modified', False),
                    'outlook_id': rec.get('outlook_id', False),
                    'owning_user_id': rec.get('owning_user_id', False),
                    'temp_id': rec.get('temp_id', False),
                    'position': rec.get('position', False),
                    'asstemail': rec.get('asstemail', False),
                    'sendpost': rec.get('sendpost', False),
                    'dissacosiate': rec.get('dissacosiate', False),
                    'modified_by': rec.get('modifiedby', False),
                    'birthday_supplier_id': rec.get('birthday_supplier_id', False),
                    'birthday_courier_id': rec.get('birthday_courier_id', False),
                    'function': rec.get('job_title', False),
                    'anniversary_supplier_id': rec.get('anniversary_supplier_id', False),
                    'anniversary_courier_id': rec.get('anniversary_courier_id', False),
                    'anniversary_date': rec.get('anniversary_date', False),
                    'account_type_id': rec.get('account_type_id', False),
                    'account_ref': rec.get('account_ref', False),
                    'id_number': rec.get('id_number', False),
                    'bank_name': rec.get('bank_name', False),
                    'account_no': rec.get('account_no', False),
                    'account_name': rec.get('account_name', False),
                    'bank_account_name': rec.get('bank_account_name', False),
                    'branch_code': rec.get('branch_code', False),
                    'acc_type_id': rec.get('acc_type_id', False),
                    'emailref': rec.get('emailref', False),
                    'credit_card_name': rec.get('credit_card_name', False),
                    'credit_card_number': rec.get('credit_card_number', False),
                    'expiry_date': rec.get('expiry_date', False),
                    'card_type_id': rec.get('card_type_id', False),
                    'is_credit_card': rec.get('is_credit_card', False),
                    'in_use': rec.get('in_use', False),
                    'exp_month': rec.get('exp_month', False),
                    'exp_year': rec.get('exp_year', False),
                    'agent_ref': rec.get('agent_ref', False),
                    'agent_id': rec.get('agnet_id', False),
                    'press': rec.get('press', False),
                    'proj_cust': rec.get('proj_cust', False),
                    'completed': rec.get('completed', False),
                    'department_id': rec.get('department_id', False),
                    'industry_id': rec.get('industry_id', False),
                    'entity_subtype_id': rec.get('entity_sub_type_id', False),
                    'use_comp_addr': rec.get('use_comp_addr', False),
                    'additional1': rec.get('additional1', False),
                    'additional2': rec.get('additional2', False),
                    'additional3': rec.get('additional3', False),
                    'additional4': rec.get('additional4', False),
                    'additional_id5': rec.get('additional_id5', False),
                    'additional_id6': rec.get('additional_id6', False),
                    'additional_id7': rec.get('additional_id7', False),
                    'additional_id8': rec.get('additional_id8', False),
                    'in_active': rec.get('in_active', False),
                    'screenshot_path': rec.get('screenshot_path', False),
                }
                # update entity contact if contact exist
                if entity_contact_id:
                    entity_contact_id.update(vals)
                else:  # create entity contact if not exist
                    partner_id.update({'child_ids': [(0, 0, vals)]})

    def action_import(self):
        """
        Import read data to the database
        """
        def _get_data(file_name, file, cell_data, req_cols, partner_check=True):
            """
            Get data for given file
            """
            try:
                file_extension = file_name.split('.')[-1]
                if file_extension == 'xlsx':
                    return self._read_xlsx_file(file, cell_data, req_cols, file_name, partner_check)
                elif file_extension == 'csv':
                    return self._read_csv_file(file, cell_data, req_cols, file_name, partner_check)
                else:
                    raise UserError(_('Selected file type is invalid. Only xlsx or csv files can be imported!'))
            except Exception as error:
                raise ValidationError(_("Following error occurred when importing file:\n\n%s" % error))

        all_invalid_lines = []
        # Read, extract and process dbo entity data
        if self.dbo_entity_file:
            dbo_entity_cell_data = {
                0: 'entity_id',
                1: 'dealer_id',
                2: 'company',
                3: 'entity_type_id',
                4: 'entity_category_id',
                5: 'entity_creator_id',
                6: 'entity_updater_id',
                7: 'abc_cat_id',
                8: 'bus_cat_id',
                9: 'notes',
                10: 'date_added',
                11: 'date_modified',
                12: 'name',
                13: 'switchboard',
                14: 'fax',
                15: 'url',
                16: 'email',
                17: 'vat',
                18: 'vat_except_num',
                19: 'accept_back_orders',
                20: 'menthod_of_contact',
                21: 'catdesc',
                22: 'website',
                23: 'comptel',
                24: 'next_call_date',
                25: 'account_type_id',
                26: 'date_updated',
                27: 'temp_id',
                28: 'compregnum',
                29: 'account_num',
                30: 'modified_by',
                31: 'account_supplier_id',
                32: 'account_customer_id',
                33: 'is_birthday_supplier',
                34: 'is_birthday_courier',
                35: 'is_anniversary_courier',
                36: 'is_anniversary_supplier',
                37: 'is_account_supplier',
                38: 'is_supplier',
                39: 'invoice_to',
                40: 'currency',
                41: 'credit_limit',
                42: 'payment_terms',
                43: 'sdl_no',
                44: 'sic_code',
                45: 'ofo_no',
                46: 'markup',
                47: 'client_rating',
                48: 'manual_rating',
                49: 'sales_cons_id',
                50: 'alternate_company_id',
                51: 'comments',
                52: 'card_type_id',
                53: 'credit_card_name',
                54: 'credit_card_number',
                55: 'exp_month',
                56: 'exp_year',
                57: 'bank_recon_notes',
                58: 'acc_stat_id',
                59: 'avg_payment_time',
                60: 'vendor_number',
                61: 'source_id',
                62: 'pricelistID',
                63: 'bank_branch_name',
                64: 'bank_branch_code',
                65: 'debit_order',
                66: 'ref_no',
                67: 'tax_type_id',
                68: 'industry_id',
                69: 'entity_subtype_id',
                70: 'temp_id_varchar',
                71: 'is_vat_exempt',
                72: 'in_active',
                73: 'cnt_order_number',
                74: 'cnt_id_number',
                75: 'cnt_damage_waiver',
                76: 'cnt_sites'
            }
            required_columns = ['entity_id', 'name']
            dbo_entity_data, invalid_lines = _get_data(self.dbo_entity_file_name, self.dbo_entity_file, dbo_entity_cell_data, required_columns, partner_check=False)
            self._process_entity_data(dbo_entity_data)
            all_invalid_lines += invalid_lines

        # Read, extract and process dbo entity address data
        if self.dbo_entity_address_file:
            dbo_entity_address_cell_data = {
                0: 'entity_address_id',
                1: 'entity_id',
                2: 'address_type',
                3: 'address_1',
                4: 'address_2',
                5: 'address_3',
                6: 'city',
                7: 'region',
                8: 'code',
                9: 'country',
                10: 'state',
                11: 'temp_id',
                12: 'is_default',
                13: 'address_4',
            }
            required_columns = ['entity_address_id', 'entity_id', 'address_type']
            dbo_entity_address_data, invalid_lines = _get_data(self.dbo_entity_address_file_name, self.dbo_entity_address_file, dbo_entity_address_cell_data, required_columns)
            self._process_entity_address_data(dbo_entity_address_data)
            all_invalid_lines += invalid_lines

        # Read, extract and process dbo entity contact data
        if self.dbo_entity_contact_file:
            dbo_entity_contact_cell_data = {
                0: 'entity_address_id',
                1: 'entity_id',
                2: 'entity_type_id',
                3: 'entity_category_id',
                4: 'alternate_contact_id',
                5: 'entity_contact_updater_id',
                6: 'entity_contact_creator_id',
                7: 'physical_addr_id',
                8: 'postal_addr_id',
                9: 'cont_type_id',
                10: 'position_id',
                11: 'interest_id',
                12: 'sales_cons_id',
                13: 'buscatid',
                14: 'abc_catid',
                15: 'is_default',
                16: 'company',
                17: 'first_name',
                18: 'surname',
                19: 'title',
                20: 'initials',
                21: 'phone',
                22: 'phone2',
                23: 'phone3',
                24: 'home_phone',
                25: 'mobile',
                26: 'fax',
                27: 'email',
                28: 'ext',
                29: 'department',
                30: 'spouse',
                31: 'asst_title',
                32: 'asst_name',
                33: 'asst_phone',
                34: 'asst_ext',
                35: 'hobbies',
                36: 'notes',
                37: 'address1',
                38: 'address2',
                39: 'address3',
                40: 'city',
                41: 'state',
                42: 'code',
                43: 'region',
                44: 'country',
                45: 'poaddress1',
                46: 'poaddress2',
                47: 'poaddress3',
                48: 'pocity',
                49: 'postate',
                50: 'pocode',
                51: 'poregion',
                52: 'pocountry',
                53: 'birth_date',
                54: 'path',
                55: 'province',
                56: 'is_supplier',
                57: 'send_email',
                58: 'send_sms',
                59: 'date_updated',
                60: 'account_num',
                61: 'entity_htype',
                62: 'date_added',
                63: 'date_modified',
                64: 'outlook_id',
                65: 'owning_user_id',
                66: 'temp_id',
                67: 'position',
                68: 'asstemail',
                69: 'sendpost',
                70: 'dissacosiate',
                71: 'modifiedby',
                72: 'birthday_supplier_id',
                73: 'birthday_courier_id',
                74: 'job_title',
                75: 'anniversary_supplier_id',
                76: 'anniversary_courier_id',
                77: 'anniversary_date',
                78: 'account_type_id',
                79: 'account_ref',
                80: 'id_number',
                81: 'bank_name',
                82: 'account_no',
                83: 'account_name',
                84: 'bank_account_name',
                85: 'branch_code',
                86: 'acc_type_id',
                87: 'emailref',
                88: 'credit_card_name',
                89: 'credit_card_number',
                90: 'expiry_date',
                91: 'card_type_id',
                92: 'is_credit_card',
                93: 'in_use',
                94: 'exp_month',
                95: 'exp_year',
                96: 'agent_ref',
                97: 'agnet_id',
                98: 'press',
                99: 'proj_cust',
                100: 'completed',
                101: 'department_id',
                102: 'industry_id',
                103: 'entity_sub_type_id',
                104: 'use_comp_addr',
                105: 'additional1',
                106: 'additional2',
                107: 'additional3',
                108: 'additional4',
                109: 'additional_id5',
                110: 'additional_id6',
                111: 'additional_id7',
                112: 'additional_id8',
                113: 'in_active',
                114: 'screenshot_path'
            }
            required_columns = ['entity_address_id', 'entity_id']
            dbo_entity_contact_data, invalid_lines = _get_data(self.dbo_entity_contact_file_name, self.dbo_entity_contact_file, dbo_entity_contact_cell_data, required_columns)
            self._process_entity_contact_data(dbo_entity_contact_data)
            all_invalid_lines += invalid_lines

        # Prepare invalid lines
        invalid_lines = [(0, 0, x) for x in all_invalid_lines]

        # return status popup
        return {
            'name': 'Import Status',
            'view_mode': 'form',
            'res_model': 'invalid.lines.wizard',
            'domain': [],
            'context': {
                'default_line_ids': invalid_lines,
                'default_successful': True if not bool(invalid_lines) else False
            },
            'type': 'ir.actions.act_window',
            'target': 'new',
        }


import streamlit as st
import numpy as np
import pandas as pd

# load model
from recommender_model import lover_recommender_test, offspring_subset

# load data
cupid_df = pd.read_pickle('data/grouped_cupid.pkl')
cupid = pd.read_pickle('data/clean_cupid.pkl')

# drop "status", "location"
cupid.drop(columns = ['status', 'location'], inplace = True)

st.set_page_config(layout = "wide", page_title = 'Lover Recommender App', page_icon = '💘')

# sidebar

st.title("💘 Lover Recommender App 💘")
st.header("Looking For A Partner? 💑👩❤👩👨❤👨")
st.markdown("----------------------------------------")

# user input features
st.subheader("Tell us a little bit about yourself first...")

# user_form = st.form(key = "my_form")

# input
age = st.number_input('How old are you?')

st.write("What's your age range?")

col1, col2 = st.beta_columns(2)
with col1:
    lowest_age = st.number_input('Lowest Age:')
with col2:
    highest_age = st.number_input('Highest Age:')

sex = st.radio('What gender do you identify as?',['m', 'f'])
orientation = st.radio('What sexual orientation do you identify with?',['straight', 'gay', 'bisexual'])
body_type = st.selectbox('What body type do you have?',('average', 'fit', 'thin', 'full figured', 'used up', 'rather not say'))
diet = st.selectbox('What does your diet consist of?',('anything', 'vegetarian', 'vegan', 'kosher', 'halal', 'other'))
drinks = st.radio('Do you consume alcoholic beverages?',['yes','no', 'sometimes'])
drugs = st.radio('Do you use drugs?',['yes', 'no', 'sometimes'])

# offspring

# do you have any children? yes/no
any_children = st.radio('Do you have any kid(s)/children?', ['yes', 'no'])

# do you want any [more] children? yes/no
more_children = st.radio('Do you want any [more] kid(s)/children?', ['yes', 'no'])

if any_children == 'no' and more_children == 'yes':
    offspring = "doesn't have kid(s), but wants kid(s)"
elif any_children == 'no' and more_children == 'no':
    offspring = "doesn't have kids, and doesn't want any"
elif any_children == 'yes' and more_children == 'no':
    offspring = "has kid(s), but doesn't want more"
elif any_children == 'yes' and more_children == 'yes':
    offspring = "has kid(s) and wants more"

pets = st.selectbox("What's your sentiment on dogs and/or cats?",('likes dogs', 'likes cats', 'likes dogs and cats', 'dislikes dogs and cats'))
smokes = st.radio('Do you smoke?',['yes', 'no', 'sometimes'])

# does religion matter?
religion = st.selectbox("Please specify your religion.", ("doesn't matter", 'agnosticism', 'christianity', 'catholicism', 'judaism', 'buddhism', 'hinduism', 'islam', 'other'))

invalue = np.array([age, sex, orientation, body_type, diet, drinks, drugs, offspring, pets, religion, smokes])

st.subheader("Show Me My Matches!!!")
click = st.checkbox("Check Here ✔")

if click:
    matches = lover_recommender_test(invalue, religion, lowest_age, highest_age)

    # show matches from OG cupid
    try:
        st.table(matches)

        st.markdown("What profile(s) catch your eye? 👀")
        options = st.multiselect("", list(matches.index))

        # keep a running df of recommended matches
        all_recs = matches

        # keep a running df of profiles liked
        liked = pd.DataFrame(columns = cupid_df.columns)
        invalue_df = pd.DataFrame(columns = cupid_df.columns)

        for value in options:
            liked = liked.append(cupid.loc[value])
            invalue_df = invalue_df.append(cupid_df.loc[value])

        # more matches
        st.markdown("Would you like to see more matches?")
        more = st.radio("", ['No', 'Yes'])

        # try:
        if more == 'Yes' and len(liked) > 0:

            # straight female
            if sex == 'f' and orientation == 'straight':
                straight_female = cupid_df[(((cupid_df['sex'] == 'm') & (cupid_df['orientation'] == 'straight')) | ((cupid_df['sex'] == 'm') & (cupid_df['orientation'] == 'bisexual'))) \
                & (cupid_df['religion'] == religion) & (cupid_df['age'] >= lowest_age) & (cupid_df['age'] <= highest_age)]

                matches = offspring_subset(invalue_df, straight_female)

            # straight male
            elif sex == 'm' and orientation == 'straight':
                straight_male = cupid_df[(((cupid_df['sex'] == 'f') & (cupid_df['orientation'] == 'straight')) | ((cupid_df['sex'] == 'f') & (cupid_df['orientation'] == 'bisexual'))) \
                    & (cupid_df['religion'] == religion) & (cupid_df['age'] >= lowest_age) & (cupid_df['age'] <= highest_age)]

                matches = offspring_subset(invalue_df, straight_male)

            # gay female
            elif sex == 'f' and orientation == 'gay':
                gay_female = cupid_df[(cupid_df['sex'] == 'f') & ((cupid_df['orientation'] == 'gay') | (cupid_df['orientation'] == 'bisexual')) & \
                    (cupid_df['religion'] == religion) & (cupid_df['age'] >= lowest_age) & (cupid_df['age'] <= highest_age)]

                matches = offspring_subset(invalue_df, gay_female)

            # gay male
            elif sex == 'm' and orientation == 'gay':
                gay_male = cupid_df[(cupid_df['sex'] == 'm') & ((cupid_df['orientation'] == 'gay') | (cupid_df['orientation'] == 'bisexual')) & \
                    (cupid_df['religion'] == religion) & (cupid_df['age'] >= lowest_age) & (cupid_df['age'] <= highest_age)]

                matches = offspring_subset(invalue_df, gay_male)

            # bi female looking for bi individual or straight male or gay female
            elif sex == 'f' and orientation == 'bisexual':
                bi_female = cupid_df[((cupid_df['sex'] == 'f') & (cupid_df['orientation'] == 'gay') & (cupid_df['religion'] == religion) & \
                        (cupid_df['age'] >= lowest_age) & (cupid_df['age'] <= highest_age)) | ((cupid_df['sex'] == 'm') & (cupid_df['orientation'] == 'straight') & \
                    (cupid_df['religion'] == religion) & (cupid_df['age'] >= lowest_age) & (cupid_df['age'] <= highest_age)) | \
                    (cupid_df['orientation'] == 'bisexual')  & (cupid_df['religion'] == religion) & (cupid_df['age'] >= lowest_age) & (cupid_df['age'] <= highest_age)]

                matches = offspring_subset(invalue_df, bi_female)

            # bi male looking for bi individual or straight female or gay male
            elif orientation == 'bisexual' and sex == 'm':
                bi_male = cupid_df[((cupid_df['sex'] == 'm') & (cupid_df['orientation'] == 'gay') & (cupid_df['religion'] == religion) & \
                        (cupid_df['age'] >= lowest_age) & (cupid_df['age'] <= highest_age)) | ((cupid_df['sex'] == 'f') & (cupid_df['orientation'] == 'straight') & \
                    (cupid_df['religion'] == religion) & (cupid_df['age'] >= lowest_age) & (cupid_df['age'] <= highest_age)) | \
                    (cupid_df['orientation'] == 'bisexual')  & (cupid_df['religion'] == religion) & (cupid_df['age'] >= lowest_age) & (cupid_df['age'] <= highest_age)]

                matches = offspring_subset(invalue_df, bi_male)

            # to return OG cupid outputs, that were based off grouped values
            # df to show users -- OG cupid
            show_users = pd.DataFrame(columns = cupid.columns)

            for value2 in matches.index:
                show_users = show_users.append(cupid.loc[value2])

            st.markdown("Here are more matches, based on the profile(s) that caught your eye earlier! 🤗")
            st.table(show_users)

            # any more profiles that users liked
            st.markdown("Any of these profiles catch your eye? 👁")
            options_more = st.multiselect("", list(show_users.index))

            for value in options_more:
                liked = liked.append(cupid.loc[value])

            # if options_more:
            #     st.subheader("Here are all the profiles you liked:")
            #     st.table(liked)
            #     st.subheader("Go on and send a message! 💌 Happy chatting! 💞💓")

        elif more == 'No':
            pass

        else:
            st.markdown("**❗❗ NOTE: If you'd like to see more matches, please select profiles from above that piqued your interest! 🙎**")

        # except:
        #     st.markdown("**NOTE: If you'd like to see more matches, please select profiles from above that piqued your interest! 🙎**")

        st.subheader("Here are all the profiles you liked:")
        st.table(liked)
        st.subheader("Go on and send a message! 💌 Happy chatting! 💞💓")

    except:
        st.image("https://media1.tenor.com/images/5a7baa3abccc024569143229fa700dd6/tenor.gif?itemid=10592594", width = 350)
        st.subheader("Apologies!! We don't have any profiles in the database that relate to your *age range*, *orientation*, *offspring sentiment* and *religious* inputs at the moment. 🙅😭")


"""
Author: Chi Zhang
Licence: MIT

This script is for cleaning / preprocessing the text.
Please refer README.md for detailed usages.
"""

import argparse as a
import re
from nltk.corpus import stopwords
from nltk.stem.wordnet import WordNetLemmatizer
from tqdm import tqdm
from typing import List
import spacy

spacy.prefer_gpu()

def parse_args():
    parser = a.ArgumentParser()
    parser.add_argument("file", type=str, help='path to plaintext file')
    parser.add_argument("--out", "-o", type=str)
    return parser.parse_args()

def clean_text(text: List[str], batch_size=200):
    """
    cleans the text by removing stopwords, punctuation, and lemmatizing the text
    Args:
        text (List[str]): list of documents, each document is a string
        batch_size (int): batch size for spacy pipeline

    Returns:
        List[str]: list of cleaned documents
    """

    # Initialize the lemmatizer and pipeline
    res = []
    lemmatizer = WordNetLemmatizer()
    pipeline = spacy.load('en_core_web_trf')

    # Process the text in batches
    for lo in tqdm(range(0, len(text), batch_size)):
        hi = min(lo + batch_size, len(text))
        text_batch = text[lo:hi]
        _stopwords = set(stopwords.words('english'))

        processed_lines = list(
            pipeline.pipe(text_batch, disable=['ner', 'parser']))
        # Remove punctuations, spaces, numbers, stopwords and lemmatize the text
        for processed_line in processed_lines:
            tokens = [
                token for token in processed_line
                if token.pos_ not in ['PUNCT', 'SPACE', 'SYM', "NUM"]
                and token.lemma_ not in _stopwords
            ]
            # Lemmatize the text again with  nltk lemmatizer
            words = [token.lemma_.lower() for token in tokens]

            # Retag each word for nltk lemmatizer
            pos_dict = {
                "NOUN": "n",
                "ADJ": "a",
                "ADV": "r",
                "VERB": "v",
            }
            pos = [pos_dict.get(token.pos_, "n") for token in tokens]
            # remove words with length less than 3 and non-alphabetic characters
            words = [
                token for token in words
                if re.match(r'^[a-zA-Z_]+$', token) and len(token) >= 3
            ]
            # Lemmatize the text with WordNetLemmatizer
            tokens = [
                lemmatizer.lemmatize(word, p) for word, p in zip(words, pos)
            ]

            res.append(' '.join(tokens))
    return res

def main():
    args = parse_args()

    f = open(args.file, 'r', encoding="utf-8")
    lines = f.readlines()
    lines = [
        line.strip().lower().replace(r'\\', ' ') for line in lines
        if len(line) > 0
    ]
    cleaned_text = clean_text(lines)
    f.close()

    f = open(args.out, 'w')
    f.write('\n'.join(cleaned_text))
    f.close()

if __name__ == "__main__":
    main()


#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import sys
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
from shiboken2 import wrapInstance
import maya.OpenMayaUI as OpenMayaUI
import maya.cmds as cmds
from . import editTangent
from ..manuWidget import boxSliderWidget as boxSliderWidget

class EditorUI(QMainWindow):
	def __init__(self,parent=None):
		super(EditorUI,self).__init__(parent)
		self.setWindowFlags(Qt.Window)
		self.resize(400,100)

		self.widget = EditorWidget(self)
		self.setCentralWidget(self.widget)
		title = self.widget.windowTitle()
		self.setWindowTitle(title)

	def closeEvent(self, e):
		try:
			self.widget.close()
		except:
			pass

class EditorWidget(QWidget):
	def __init__(self,parent=None):
		super(EditorWidget,self).__init__(parent)
		self.setWindowTitle('Curve Editor')
		self.initUI()

	def initUI(self):
		self.widget_t = TanSliderWidget(self)
		self.widget_w = WgtSliderWidget(self)
		layout = QVBoxLayout()
		layout.addWidget(self.widget_t)
		layout.addWidget(self.widget_w)
		self.setLayout(layout)

	def closeEvent(self, e):
		try:
			self.widget_t.close()
			self.widget_w.close()
		except:
			pass

class TanSliderWidget(QWidget):
	def __init__(self,parent=None):
		super(TanSliderWidget,self).__init__(parent)
		self.setWindowTitle('Tangent Editor')
		self.initUI()

	def initUI(self):
		self.boxSlider = boxSliderWidget.BoxSliderWidget(self,-90,90)
		self.boxSlider.funcValueChanged = self.changed_editor

		# maya上から値を拾っている
		if editTangent.check_animation():
			self.set_ui_value(1)
		else:
			self.boxSlider.slider.setValue(0)
			self.boxSlider.dspinBox.setValue(0)

		#　ラジオボタンとか
		self.radioIo_A = QRadioButton('both',self)
		self.radioIo_A.setChecked(True)
		self.radioIo_B = QRadioButton('in',self)
		self.radioIo_C = QRadioButton('out',self)
		self.radioIoGroup = QButtonGroup()
		self.radioIoGroup.addButton(self.radioIo_A,1)
		self.radioIoGroup.addButton(self.radioIo_B,2)
		self.radioIoGroup.addButton(self.radioIo_C,3)

		self.radioIo_A.setFixedWidth(50)
		self.radioIo_B.setFixedWidth(50)
		self.radioIo_C.setFixedWidth(50)

		self.tangentLlabel = QLabel('Tangent :',self)

		self.radioIoGroup.buttonClicked[int].connect(self.set_ui_value)

		# レイアウト決め
		self.vLayout = QVBoxLayout()

		self.hLayout_A = QHBoxLayout()
		self.hLayout_A.addWidget(self.tangentLlabel)
		self.hLayout_A.addWidget(self.radioIo_A)
		self.hLayout_A.addWidget(self.radioIo_B)
		self.hLayout_A.addWidget(self.radioIo_C)
		self.hLayout_A.addStretch()
		self.vLayout.addLayout(self.hLayout_A)

		self.hlayout_b = QHBoxLayout()
		self.hlayout_b.addWidget(self.boxSlider)
		self.vLayout.addLayout(self.hlayout_b)
		self.scriptNo = []
		self.scriptNo.append(cmds.scriptJob(e=["SelectionChanged",self.changed_selection]))
		self.scriptNo.append(cmds.scriptJob(e=["Redo",self.changed_selection]))
		self.scriptNo.append(cmds.scriptJob(e=["Undo",self.changed_selection]))
		self.vLayout.setContentsMargins(0, 0, 0, 0)
		self.vLayout.setSpacing(0)
		self.setLayout(self.vLayout)

	def closeEvent(self, e):
		if self.scriptNo:
			for no in self.scriptNo:
				cmds.scriptJob(k=no)

	def changed_editor(self):
		if editTangent.check_animation():
			editTangent.set_angle(self.radioIoGroup.checkedId(),self.boxSlider.dspinBox.value())

	def changed_selection(self):
		io = self.radioIoGroup.checkedId()
		self.set_ui_value(io)

	def set_ui_value(self,io):
		if editTangent.check_animation():
			self.boxSlider.blockSignals(True)
			self.boxSlider.slider.setValue(editTangent.get_angle(io) * 100)
			self.boxSlider.dspinBox.setValue(editTangent.get_angle(io))
			self.boxSlider.blockSignals(False)
		else:
			self.boxSlider.blockSignals(True)
			self.boxSlider.slider.setValue(0)
			self.boxSlider.dspinBox.setValue(0)
			self.boxSlider.blockSignals(False)

class WgtSliderWidget(TanSliderWidget):
	def __init__(self,parent=None):
		super(WgtSliderWidget,self).__init__(parent)
		self.setWindowTitle('Weight Editor')

	def initUI(self):
		self.boxSlider = boxSliderWidget.BoxSliderWidget(self,0,100)
		self.boxSlider.funcValueChanged = self.changed_editor

		# maya上から値を拾っている
		if editTangent.check_animation():
			self.set_ui_value(1)
		else:
			self.boxSlider.slider.setValue(0)
			self.boxSlider.dspinBox.setValue(0)

		#　ラジオボタンとか
		self.radioIo_A = QRadioButton('both',self)
		self.radioIo_A.setChecked(True)
		self.radioIo_B = QRadioButton('in',self)
		self.radioIo_C = QRadioButton('out',self)
		self.radioIoGroup = QButtonGroup()
		self.radioIoGroup.addButton(self.radioIo_A,1)
		self.radioIoGroup.addButton(self.radioIo_B,2)
		self.radioIoGroup.addButton(self.radioIo_C,3)

		self.radioIo_A.setFixedWidth(50)
		self.radioIo_B.setFixedWidth(50)
		self.radioIo_C.setFixedWidth(50)

		self.weighLlabel = QLabel('Weight :',self)

		self.radioIoGroup.buttonClicked[int].connect(self.set_ui_value)

		self.checkBox = QCheckBox('Weight Tangent',self)
		self.set_weight_checkBox()
		self.checkBox.stateChanged.connect(editTangent.toggle_wieghtTangent)

		# レイアウト決め
		self.vLayout = QVBoxLayout()

		self.hLayout_A = QHBoxLayout()
		self.hLayout_A.addWidget(self.weighLlabel)
		self.hLayout_A.addWidget(self.radioIo_A)
		self.hLayout_A.addWidget(self.radioIo_B)
		self.hLayout_A.addWidget(self.radioIo_C)
		self.hLayout_A.addWidget(self.checkBox)
		self.hLayout_A.addStretch()
		self.vLayout.addLayout(self.hLayout_A)

		self.hlayout_b = QHBoxLayout()
		self.hlayout_b.addWidget(self.boxSlider)
		self.vLayout.addLayout(self.hlayout_b)
		self.scriptNo = []
		self.scriptNo.append(cmds.scriptJob(e=["SelectionChanged",self.changed_selection]))
		self.scriptNo.append(cmds.scriptJob(e=["Redo",self.changed_selection]))
		self.scriptNo.append(cmds.scriptJob(e=["Undo",self.changed_selection]))
		self.vLayout.setContentsMargins(0, 0, 0, 0)
		self.vLayout.setSpacing(0)
		self.setLayout(self.vLayout)

	def changed_editor(self):
		if editTangent.check_animation():
			editTangent.set_weight(self.radioIoGroup.checkedId(),self.boxSlider.dspinBox.value())

	def changed_selection(self):
		self.set_weight_checkBox()
		io = self.radioIoGroup.checkedId()
		self.set_ui_value(io)

	def set_weight_checkBox(self):
		self.checkBox.blockSignals(True)
		if editTangent.check_animation():
			self.checkBox.setChecked(editTangent.get_weightTangent())
		else:
			self.checkBox.setChecked(False)
		self.checkBox.blockSignals(False)

	def set_ui_value(self,io):
		if editTangent.check_animation():
			self.boxSlider.blockSignals(True)
			self.boxSlider.slider.setValue(editTangent.get_weight(io) * 100)
			self.boxSlider.dspinBox.setValue(editTangent.get_weight(io))
			self.boxSlider.blockSignals(False)
		else:
			self.boxSlider.blockSignals(True)
			self.boxSlider.slider.setValue(0)
			self.boxSlider.dspinBox.setValue(0)
			self.boxSlider.blockSignals(False)

def main():
	mayaWindow = 'graphEditor1Window' #常にこのウィンドウより前にいます
	ptr = OpenMayaUI.MQtUtil.findWindow(mayaWindow)
	if ptr is not None:
		parent = wrapInstance(int(ptr),QWidget)
	else:
		cmds.error('Please open the GraphEditor')
	app = QApplication.instance()
	ui = EditorUI(parent)
	ui.show()
	sys.exit()
	app.exec_()

if __name__ == "__main__":
	main()


import datetime
import json
import secrets
import uuid
from typing import Any, Dict, List, Optional, Tuple, Union

import bcrypt
import jwt
import jwt.algorithms
import jwt.exceptions
import requests
import uvicorn
from fastapi import Depends, Header, HTTPException, Request, status
from fastapi.responses import RedirectResponse
from fastapi.routing import APIRouter
from fastapi.security import APIKeyCookie, HTTPBasic, HTTPBasicCredentials
from fastapi.security.utils import get_authorization_scheme_param
from pydantic import BaseModel
from sqlalchemy import and_

from workspacesio import database, depends, models
from workspacesio.common import schemas
from workspacesio.settings import settings
from workspacesio.utils import build_url

## These schemas are separate from the main schemas
## because they should never be used external to this file

class JWToken(BaseModel):
    email: str
    sub: str  # primary key
    iat: int
    exp: int

    given_name: Optional[str]
    nickname: Optional[str]
    picture: Optional[str]

    verified: bool = False

class OIDCJWTokenResponse(BaseModel):
    id_token: str
    access_token: str
    expires_in: int
    refresh_expires_in: Optional[int]
    refresh_token: Optional[str]
    token_type: str
    scope: str

class OIDCWellKnown(BaseModel):
    issuer: str
    token_endpoint: str
    authorization_endpoint: str
    jwks_uri: str

class OIDCKeys(BaseModel):
    keys: List[Dict[str, Union[str, List[str]]]]

class OIDCConfig(BaseModel):
    well_known: OIDCWellKnown
    keys: Dict[str, Any]

router = APIRouter()
sessioncookie = APIKeyCookie(name="session", auto_error=False)
security = HTTPBasic(auto_error=False)
oidc_conf: Union[OIDCConfig, None] = None

def _openid_config():
    global oidc_conf
    if oidc_conf is None:
        wellknown_resp = requests.get(settings.oidc_well_known_url)
        wellknown_resp.raise_for_status()
        wellknown = OIDCWellKnown(**wellknown_resp.json())

        keys_resp = requests.get(wellknown.jwks_uri)
        keys_resp.raise_for_status()
        keys = OIDCKeys(**keys_resp.json())

        public_keys: Dict[str, Any] = {}
        for jwk in keys.keys:
            kid = jwk["kid"]
            public_keys[kid] = jwt.algorithms.RSAAlgorithm.from_jwk(json.dumps(jwk))

        oidc_conf = OIDCConfig(
            well_known=wellknown,
            keys=public_keys,
        )
    yield oidc_conf

def _verify_jwt(token: str, config: OIDCConfig, verify=True) -> JWToken:
    kid = jwt.get_unverified_header(token)["kid"]
    key = config.keys.get(kid)
    if key is None:
        raise HTTPException(
            status.HTTP_400_BAD_REQUEST, "key ID not found in openid config"
        )

    # Audience is tricky
    # https://github.com/jpadilla/pyjwt/issues/198
    # https://auth0.com/docs/tokens/access-tokens/get-access-tokens
    decoded = jwt.decode(
        token,
        key,
        algorithms=settings.oidc_algos,
        audience=settings.oidc_client_id,
        verify=verify,
    )
    return JWToken(**decoded, verified=verify)

def _verify_token(token, hashed_token):
    pass

def _maybe_session_user(
    session: str = Depends(sessioncookie),
    config: OIDCConfig = Depends(_openid_config),
    db: database.SessionLocal = Depends(depends.get_db),
) -> Optional[JWToken]:
    """
    Load user without verifying session.
    """
    if session is None:
        return None

    try:
        return _verify_jwt(session, config)
    except jwt.exceptions.PyJWTError as e:
        return _verify_jwt(session, config, verify=False)

def _make_redirect(config: OIDCConfig, token: Optional[JWToken]) -> RedirectResponse:
    # https://auth0.com/docs/api/authentication#dynamic-application-client-registration
    args = {
        "response_type": "code",
        "client_id": settings.oidc_client_id,
        "scope": "openid given_name email picture nickname",
        "redirect_uri": build_url(settings.public_name, "/auth"),
    }
    if token is not None:
        # attempt a silent auth
        args["prompt"] = "none"
    return RedirectResponse(
        url=build_url(config.well_known.authorization_endpoint, args_dict=args)
    )

def get_current_user(
    session_cookie: Optional[JWToken] = Depends(_maybe_session_user),
    credentials: HTTPBasicCredentials = Depends(security),
    db: database.SessionLocal = Depends(depends.get_db),
) -> models.User:

    if session_cookie is not None and session_cookie.verified:
        user = (
            db.query(models.User).filter(models.User.sub == session_cookie.sub).first()
        )
        if user is not None:
            return user
    if credentials:
        apikey: Optional[models.ApiKey] = (
            db.query(models.ApiKey)
            .filter(models.ApiKey.key_id == credentials.username)
            .first()
        )
        if apikey is not None:
            verified = apikey.verify(credentials.password)
            if verified:
                return apikey.user
    raise HTTPException(status.HTTP_401_UNAUTHORIZED, "Unauthorized")

@router.get("/login")
async def login(
    config: OIDCConfig = Depends(_openid_config),
    token: Optional[JWToken] = Depends(_maybe_session_user),
) -> RedirectResponse:
    return _make_redirect(config, token)

@router.get("/logout")
def logout():
    response = RedirectResponse(url="/app")
    response.set_cookie("session", value="", samesite="lax", httponly=True, expires=0)
    return response

@router.get("/auth")
async def auth(
    code: Optional[str] = None,
    error: Optional[str] = None,
    config: OIDCConfig = Depends(_openid_config),
    db: database.SessionLocal = Depends(depends.get_db),
) -> RedirectResponse:
    if error is not None:
        return _make_redirect(config, None)
    if code is None:
        raise HTTPException(400, "No error, code missing.")
    # https://auth0.com/docs/api/authentication#get-token
    resp = requests.post(
        config.well_known.token_endpoint,
        data={
            "grant_type": "authorization_code",
            "code": code,
            "redirect_uri": build_url(settings.public_name, "/auth"),
            "client_id": settings.oidc_client_id,
            "client_secret": settings.oidc_client_secret,
        },
    )
    resp.raise_for_status()
    token = OIDCJWTokenResponse(**resp.json())
    verified = _verify_jwt(token.id_token, config)

    user: schemas.UserDB = (
        db.query(models.User).filter(models.User.sub == verified.sub).first()
    )

    if user is None:
        user = models.User(
            username=verified.nickname or verified.email,
            email=verified.email,
            sub=verified.sub,
        )
        db.add(user)
        db.commit()

    response = RedirectResponse(url="/app")
    response.set_cookie("session", value=token.id_token, samesite="lax", httponly=True)
    return response

@router.get("/")
def root(session: str = Depends(sessioncookie)) -> RedirectResponse:
    return RedirectResponse(url="/app")


from typing import Iterable
from typing import List
from typing import Optional
from typing import Tuple
from typing import Union

import numpy as np
import torch

from nncf.common.graph import Dtype

class TensorMeta:
    @staticmethod
    def default_comparator(lhs: 'TensorMeta', rhs: 'TensorMeta'):
        return lhs.index == rhs.index and lhs.creator_id == rhs.creator_id and lhs.shape[1:] == rhs.shape[1:]

    def __init__(self, creator_id: int, index: int, shape: Union[List[int], Tuple[torch.Tensor, ...]],
                 dtype: Dtype = Dtype.FLOAT):
        """
        :param creator_id: An ID of the node in DynamicGraph that corresponds to an operation that created the
            tensor.
        :param index: The index of this tensor in the creator operation's output.
        :param shape: The shape of the tensor.
        """
        self.creator_id = creator_id
        self.index = index
        self.shape = tuple(int(dim) for dim in shape)  # Handle cases when shape is a tuple of Tensors
        self.dtype = dtype

    def __eq__(self, other):
        if not isinstance(other, TensorMeta):
            return False
        return self.default_comparator(self, other)

    def __hash__(self):
        return hash((self.creator_id, self.index, self.shape))

    def __str__(self):
        return "C{}_I{}_".format(self.creator_id, self.index) + "S" + "x".join([str(s) for s in self.shape])

class TracedTensor(torch.Tensor):
    # pylint: disable=abstract-method
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.tensor_meta = None

    @staticmethod
    def from_torch_tensor(tensor, tensor_meta: TensorMeta):
        tensor.tensor_meta = tensor_meta
        tensor.__class__ = TracedTensor
        return tensor

    def as_subclass(self, cls: 'TracedTensor') -> 'TracedTensor':
        """
        Required for PyTorch 1.7.0 compatibility - the handle_torch_function and __torch_function__
        API in general calls this after a wrapped function call; need to preserve the tensor_meta extensions
        """

        return self

    # NOTE: This disables the __torch_function__ API altogether when using NNCF.
    # TODO: make NNCF utilize the __torch_function__ API instead.
    #pylint:disable=protected-access
    if hasattr(torch._C, "_disabled_torch_function_impl"):
        __torch_function__ = torch._C._disabled_torch_function_impl

def is_iterable(item):
    non_iterable_types = (str, bytes, bytearray, torch.Tensor, np.ndarray)
    # pylint:disable=isinstance-second-argument-not-valid-type
    return isinstance(item, Iterable) and not isinstance(item, non_iterable_types)

def flatten(items):
    it = items.items() if hasattr(items, 'items') else iter(items)
    for item in it:
        if is_iterable(item):
            for i in flatten(item):
                yield i
        else:
            yield item

def flatten_args(args, kwargs):
    return list(flatten(args)) + list(flatten(kwargs))

def get_dtype(x: torch.Tensor) -> Dtype:
    if x.dtype in [torch.float, torch.float16, torch.float32, torch.float64]:
        return Dtype.FLOAT
    return Dtype.INTEGER

def trace_tensors(operator_output, node: 'DynamicGraphNode'):
    if isinstance(operator_output, (list, tuple)):
        output_ = []
        for i, x in enumerate(operator_output):
            meta = None
            if node is not None:
                meta = TensorMeta(node.node_id, i, x.shape, get_dtype(x))
            output_.append(TracedTensor.from_torch_tensor(x, meta))
        return operator_output.__class__(output_)
    if isinstance(operator_output, torch.Tensor):
        meta = None
        if node is not None:
            meta = TensorMeta(node.node_id, 0, operator_output.shape, get_dtype(operator_output))
        return TracedTensor.from_torch_tensor(operator_output, meta)
    raise ValueError("Unknown return type. Can not trace function call")

def make_tensor_metas(inputs: 'OperatorInput') -> List[Optional[TensorMeta]]:
    tensor_metas = []
    for i, node_input_index_entry in enumerate(inputs):
        node_input = node_input_index_entry.getter()
        if isinstance(node_input, TracedTensor):
            tensor_metas.append(node_input.tensor_meta)
        elif isinstance(node_input, torch.Tensor) and not isinstance(node_input, TracedTensor):
            meta = TensorMeta(None, i, node_input.shape)
            tensor_metas.append(meta)
        else:
            tensor_metas.append(None)
    return tensor_metas


from django.urls import path
from .views import product_list , sales_list ,add_sale , error, stock_list,purchase_list,add_purchase,dashboard

urlpatterns = [
    path('products/', product_list, name='product_list'),
    path('sales/', sales_list, name='sales_list'),
    path('purchases/', purchase_list, name='purchase_list'),
    path('add_sale/', add_sale, name='add_sale'),
    path('add_purchase/', add_purchase, name='add_purchase'),
    path('stocks/', stock_list, name='stock_list'),
    path('dashboard/', dashboard, name='dashboard'),
    path('error/', error, name='error'),

    # Add other URL patterns for purchase, sale, supplier, customer, and stock as needed
]


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
__copyright__ = """ This code is licensed under the 3-clause BSD license.
Copyright ETH Zurich, Laboratory of Physical Chemistry, Reiher Group.
See LICENSE.txt for details.
"""
"""
Provides the ServerProcess class.
"""

import socket
from typing import Optional
from multiprocessing import Process
from scine_heron.mediator_potential.mediator_server import run_server
from .clientserver import send_data

class ServerProcess:
    def __init__(self) -> None:
        self.is_server_running = False
        self.__server_process: Optional[Process] = None

    def start(self) -> None:
        if self.__server_process is None:
            self.__server_process = Process(target=run_server, args=())
            self.__server_process.start()

    @staticmethod
    def __send_stop_signal() -> None:
        stop_signal = True
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.connect(("127.0.0.1", 55145))
            send_data(data=[stop_signal, None, None, None], socket=s)

    def stop(self) -> None:
        if self.__server_process is not None:
            self.__send_stop_signal()
            self.__server_process.join()
            self.__server_process = None


from functools import partial
from typing import Dict, Type, Tuple

import pytest
import torch

from nncf.common.tensor_statistics.statistics import TensorStatistic
from nncf.common.tensor_statistics.collectors import TensorStatisticCollectorBase, ReductionShape, \
    StatisticsNotCollectedError, OfflineTensorStatisticCollector
from nncf.torch.tensor_statistics.collectors import PTMinMaxStatisticCollector, PTMixedMinMaxStatisticCollector, \
    PTMeanMinMaxStatisticCollector, PTMedianMADStatisticCollector, PTPercentileStatisticCollector, \
    PTMeanPercentileStatisticCollector
from nncf.torch.tensor_statistics.collectors import PTNNCFCollectorTensorProcessor
from nncf.torch.tensor_statistics.statistics import PTMinMaxTensorStatistic, \
    PTMedianMADTensorStatistic, PTPercentileTensorStatistic
from nncf.torch.tensor import PTNNCFTensor

class TestCollectedStatistics:
    REF_INPUTS = [
        torch.tensor([
            [1.0, 2.0, 3.0],
            [-1.0, -2.0, -3.0],
            [4.0, 5.0, 6.0]
        ]),
        torch.tensor([
            [4.5, 2.6, 3.7],
            [-1.3, -4, -3.5],
            [4.3, 5.8, 6.1]
        ])
    ]

    @pytest.mark.parametrize(('collector', 'reduction_shapes_vs_ref_statistic'),
                             [
                                 (
                                         PTMinMaxStatisticCollector,
                                         {
                                             ((1,), (0, 1)): PTMinMaxTensorStatistic(min_values=torch.tensor([-4.0]),
                                                                                max_values=torch.tensor([6.1])),
                                             ((3, 1), (1,)): PTMinMaxTensorStatistic(
                                                 min_values=torch.tensor([[1.0], [-4.0], [4.0]]),
                                                 max_values=torch.tensor([[4.5], [4.0], [6.1]])),
                                             ((1, 3), (0,)): PTMinMaxTensorStatistic(
                                                 min_values=torch.tensor([[-1.3, -4.0, -3.5]]),
                                                 max_values=torch.tensor([[4.5, 5.8, 6.1]])),
                                             # Not supported for now:
                                             # ((3, 3), ): PTMinMaxTensorStatistic(
                                             #     min_values=torch.tensor([
                                             #         [1.0, 2.0, 3.0],
                                             #         [-1.3, -4, -3.5],
                                             #         [4.0, 5.0, 6.0]
                                             #     ]),
                                             #     max_values=torch.tensor([
                                             #         [4.5, 2.6, 3.7],
                                             #         [1.3, 4.0, 3.5],
                                             #         [4.3, 5.8, 6.1]
                                             #     ]),
                                             # ),
                                         }
                                 ),
                                 (
                                         partial(PTMeanMinMaxStatisticCollector, use_per_sample_stats=False),
                                         {
                                             ((1,), (0, 1)): PTMinMaxTensorStatistic(min_values=torch.tensor([-3.5]),
                                                                                max_values=torch.tensor([6.05])),
                                             ((3, 1), (1,)): PTMinMaxTensorStatistic(
                                                 min_values=torch.tensor([[1.8], [-3.5], [4.15]]),
                                                 max_values=torch.tensor([[3.75], [3.5], [6.05]])),
                                             ((1, 3), (0,)): PTMinMaxTensorStatistic(
                                                 min_values=torch.tensor([[-1.15, -3, -3.25]]),
                                                 max_values=torch.tensor([[4.25, 5.4, 6.05]])),
                                         }
                                 ),
                                 (
                                         partial(PTMixedMinMaxStatisticCollector,
                                                 use_per_sample_stats=False,
                                                 use_means_of_mins=False,
                                                 use_means_of_maxs=True),
                                         {
                                             ((1,), (0, 1)): PTMinMaxTensorStatistic(min_values=torch.tensor([-4.0]),
                                                                                max_values=torch.tensor([6.05])),
                                             ((3, 1), (1,)): PTMinMaxTensorStatistic(
                                                 min_values=torch.tensor([[1.0], [-4.0], [4.0]]),
                                                 max_values=torch.tensor([[3.75], [3.5], [6.05]])),
                                             ((1, 3), (0,)): PTMinMaxTensorStatistic(
                                                 min_values=torch.tensor([[-1.3, -4.0, -3.5]]),
                                                 max_values=torch.tensor([[4.25, 5.4, 6.05]])),
                                         }
                                 )
                             ])
    def test_collected_statistics_with_shape_convert(self, collector: Type[TensorStatisticCollectorBase],
                                                     reduction_shapes_vs_ref_statistic:
                                                     Dict[Tuple[ReductionShape, ReductionShape], TensorStatistic]):
        for shapes in reduction_shapes_vs_ref_statistic.keys():
            output_shape, reduction_shape = shapes
            collector_obj = collector(use_abs_max=True,
                                      reduction_shape=reduction_shape,
                                      output_shape=output_shape)
            for input_ in TestCollectedStatistics.REF_INPUTS:
                collector_obj.register_input(input_)
            test_stats = collector_obj.get_statistics()
            assert reduction_shapes_vs_ref_statistic[shapes] == test_stats

    @pytest.mark.parametrize(('collector', 'reduction_shapes_vs_ref_statistic'),
                             [
                                 (
                                         PTMedianMADStatisticCollector,
                                         {
                                             (1,): PTMedianMADTensorStatistic(median_values=torch.tensor([2.8]),
                                                                              mad_values=torch.tensor([2.6])),
                                             (3, 1): PTMedianMADTensorStatistic(
                                                 median_values=torch.tensor([[2.8], [-2.5], [5.4]]),
                                                 mad_values=torch.tensor([[0.85], [1.1], [0.65]])),
                                             (1, 3): PTMedianMADTensorStatistic(
                                                 median_values=torch.tensor([[2.5, 2.3, 3.35]]),
                                                 mad_values=torch.tensor([[1.9, 3.1, 2.7]])),
                                             # Not supported for now:
                                             # (3, 3): PTMedianMADTensorStatistic(
                                             #     median_values=torch.tensor([
                                             #         [2.75, 2.3, 3.35],
                                             #         [-1.15, -3, -3.25],
                                             #         [4.15, 5.4, 6.05]
                                             #     ]),
                                             #     mad_values=torch.tensor([
                                             #         [1.75, 0.3, 0.35],
                                             #         [0.15, 1, 0.25],
                                             #         [0.15, 0.4, 0.05]
                                             #     ]),
                                             # ),
                                         }
                                 ),
                                 (
                                         partial(PTPercentileStatisticCollector, percentiles_to_collect=[10.0]),
                                         {
                                             (1,): PTPercentileTensorStatistic(
                                                 {10.0: torch.tensor([-3.15])}),
                                             (3, 1): PTPercentileTensorStatistic(
                                                 {10.0: torch.tensor([[1.5], [-3.75], [4.15]])}),
                                             (1, 3): PTPercentileTensorStatistic(
                                                 {10.0: torch.tensor([[-1.15, -3, -3.25]])}),
                                             # Not supported for now:
                                             # (3, 3): PTPercentileTensorStatistic(
                                             #     {
                                             #         10.0: torch.tensor([
                                             #             [1.35, 2.06, 3.07],
                                             #             [-1.27, -3.8, -3.45],
                                             #             [4.03, 5.08, 6.01]
                                             #         ])
                                             #     }
                                             # ),
                                         }
                                 ),
                                 (
                                         partial(PTMeanPercentileStatisticCollector, percentiles_to_collect=[10.0]),
                                         {
                                             (1,): PTPercentileTensorStatistic(
                                                 {10.0: torch.tensor([-2.9])}),
                                             (3, 1): PTPercentileTensorStatistic(
                                                 {10.0: torch.tensor([[ 2.0100], [-3.3500], [ 4.4000]])}),
                                             (1, 3): PTPercentileTensorStatistic(
                                                 {10.0: torch.tensor([[-0.3900, -1.9400, -1.9300]])}),
                                             # Not supported for now:
                                             # (3, 3): PTPercentileTensorStatistic(
                                             #     {
                                             #         10.0: torch.tensor([
                                             #             [ 2.7500,  2.3000,  3.3500],
                                             #             [-1.1500, -3.0000, -3.2500],
                                             #             [ 4.1500,  5.4000,  6.0500]
                                             #         ])
                                             #     }
                                             # ),
                                         }
                                 ),
                             ])
    def test_collected_statistics(self, collector: Type[TensorStatisticCollectorBase],
                                  reduction_shapes_vs_ref_statistic: Dict[ReductionShape, TensorStatistic]):
        for shapes in reduction_shapes_vs_ref_statistic.keys():
            reduction_shape = shapes
            collector_obj = collector(reduction_shape=reduction_shape)
            for input_ in TestCollectedStatistics.REF_INPUTS:
                collector_obj.register_input(input_)
            test_stats = collector_obj.get_statistics()
            assert reduction_shapes_vs_ref_statistic[shapes] == test_stats

    COLLECTORS = [
        partial(PTMinMaxStatisticCollector,
                use_abs_max=False,
                output_shape=(1,)),
        partial(PTMixedMinMaxStatisticCollector,
                use_per_sample_stats=False,
                use_abs_max=False,
                use_means_of_mins=False,
                use_means_of_maxs=False,
                output_shape=(1,)),
        partial(PTMeanMinMaxStatisticCollector,
                use_per_sample_stats=False,
                use_abs_max=False,
                output_shape=(1,)),
        PTMedianMADStatisticCollector,
        partial(PTPercentileStatisticCollector, percentiles_to_collect=[10.0]),
        partial(PTMeanPercentileStatisticCollector, percentiles_to_collect=[10.0])]

    @pytest.fixture(params=COLLECTORS)
    def collector_for_interface_test(self, request):
        collector_type = request.param
        return collector_type(reduction_shape=(1,))

    def test_collected_samples(self, collector_for_interface_test: TensorStatisticCollectorBase):
        for input_ in TestCollectedStatistics.REF_INPUTS:
            collector_for_interface_test.register_input(input_)
        assert collector_for_interface_test.collected_samples() == len(TestCollectedStatistics.REF_INPUTS)

    def test_reset(self, collector_for_interface_test: TensorStatisticCollectorBase):
        for input_ in TestCollectedStatistics.REF_INPUTS:
            collector_for_interface_test.register_input(input_)
        collector_for_interface_test.reset()
        assert collector_for_interface_test.collected_samples() == 0
        with pytest.raises(StatisticsNotCollectedError):
            collector_for_interface_test.get_statistics()

    def test_enable_disable(self, collector_for_interface_test: TensorStatisticCollectorBase):
        for input_ in TestCollectedStatistics.REF_INPUTS:
            collector_for_interface_test.register_input(input_)

        collector_for_interface_test.disable()
        for input_ in TestCollectedStatistics.REF_INPUTS:
            collector_for_interface_test.register_input(input_)
        assert collector_for_interface_test.collected_samples() == len(TestCollectedStatistics.REF_INPUTS)

        collector_for_interface_test.enable()
        for input_ in TestCollectedStatistics.REF_INPUTS:
            collector_for_interface_test.register_input(input_)
        assert collector_for_interface_test.collected_samples() == 2 * len(TestCollectedStatistics.REF_INPUTS)

    OFFLINE_COLLECTORS = [
        partial(PTMixedMinMaxStatisticCollector,
                use_per_sample_stats=False,
                use_abs_max=False,
                use_means_of_mins=False,
                use_means_of_maxs=False,
                output_shape=(1,)),
        partial(PTMeanMinMaxStatisticCollector,
                use_per_sample_stats=False,
                use_abs_max=False,
                output_shape=(1,)),
        PTMedianMADStatisticCollector,
        partial(PTPercentileStatisticCollector, percentiles_to_collect=[10.0]),
        partial(PTMeanPercentileStatisticCollector, percentiles_to_collect=[10.0]),
    ]

    REF_NUM_SAMPLES = 3
    @pytest.fixture(params=OFFLINE_COLLECTORS)
    def collector_for_num_samples_test(self, request):
        collector_type = request.param
        return collector_type(reduction_shape=(1,),
                              num_samples=TestCollectedStatistics.REF_NUM_SAMPLES)

    def test_num_samples(self, collector_for_num_samples_test: OfflineTensorStatisticCollector):
        for input_ in TestCollectedStatistics.REF_INPUTS * 10:
            collector_for_num_samples_test.register_input(input_)
        assert collector_for_num_samples_test.collected_samples() == TestCollectedStatistics.REF_NUM_SAMPLES

class TestCollectorTensorProcessor:
    tensor_processor = PTNNCFCollectorTensorProcessor()

    def test_unstack(self):
        # Unstack tensor with dimensions
        tensor1 = torch.tensor([1.0])
        tensor_unstacked1 = TestCollectorTensorProcessor.tensor_processor.unstack(PTNNCFTensor(tensor1))

        # Unstack dimensionless tensor
        tensor2 = torch.tensor(1.0)
        tensor_unstacked2 = TestCollectorTensorProcessor.tensor_processor.unstack(PTNNCFTensor(tensor2))

        assert tensor_unstacked1 == tensor_unstacked2 == [PTNNCFTensor(torch.tensor(1.0))]


#!/usr/bin/python3
""" TOKEN SECTIONING MODULE """
from transformers import GPT2Tokenizer

tokenizer = GPT2Tokenizer.from_pretrained("gpt2")

def get_tokens(df):
    df['Tokens'] = ""
    for i in df.index:
        b = df.loc[i]
        text = " ".join([m for n in b for m in str(n).split()])
        tokens2 = tokenizer(text)['input_ids']
        df['Tokens'].loc[i] = len(
            [tokenizer.decode(x).strip() for x in tokens2])
    return df

def get_sections(df):
    count = 0
    df = get_tokens(df)
    total_tokens = df["Tokens"].sum()
    print(f"Total {total_tokens}")
    i = df.index.start
    while i < df.index.stop:
        if (count + df.loc[i]["Tokens"]) < 900:
            count += df.loc[i]["Tokens"]
            x = df.loc[i]["Tokens"]
            print(f"Tokens {x} ---- sections {count}")
            if df.loc[i]["Tokens"] == 0:
                print(i, df.loc[i], df.loc[i + 1])
            i += 1
        else:
            i -= 1
            break
    return df.loc[:i].drop("Tokens", axis=1)