"""Restrictions on on ontology classes."""

import logging
from enum import Enum

import rdflib
from rdflib.term import BNode

from osp.core.ontology.attribute import OntologyAttribute
from osp.core.ontology.relationship import OntologyRelationship

logger = logging.getLogger(__name__)

class QUANTIFIER(Enum):
    """The different quantifiers for restrictions."""

    SOME = 1
    ONLY = 2
    EXACTLY = 3
    MIN = 4
    MAX = 5
    VALUE = 6

class RTYPE(Enum):
    """The two types of restrictions."""

    ATTRIBUTE_RESTRICTION = 1
    RELATIONSHIP_RESTRICTION = 2

class Restriction:
    """A class to represet restrictions on ontology classes."""

    def __init__(self, bnode, namespace_registry):
        """Initialize the restriction class.

        Args:
            bnode (BNode): The blank node that represents the restriction.
            namespace_registry (NamespaceRegistry): The global namespace
                registry that contains all the OSP-core namespaces.
        """
        self._bnode = bnode
        self._graph = namespace_registry._graph
        self._namespace_registry = namespace_registry
        self._cached_quantifier = None
        self._cached_property = None
        self._cached_target = None
        self._cached_type = None

    def __str__(self):
        """Transform to string."""
        return " ".join(
            map(str, (self._property, self.quantifier, self.target))
        )

    @property
    def quantifier(self):
        """Get the quantifier of the restriction.

        Returns:
            QUANTIFIER: The quantifier of the restriction.
        """
        if self._cached_quantifier is None:
            self._compute_target()
        return self._cached_quantifier

    @property
    def target(self):
        """The target ontology class or datatype.

        Returns:
            Union[OntologyClass, UriRef]: The target class or datatype.
        """
        if self._cached_target is None:
            self._compute_target()
        return self._cached_target

    @property
    def relationship(self):
        """The relationship the RELATIONSHIP_RESTRICTION acts on.

        Raises:
            AttributeError: Called on an ATTRIBUTE_RESTRICTION.

        Returns:
            OntologyRelationship: The relationship the restriction acts on.
        """
        if self.rtype == RTYPE.ATTRIBUTE_RESTRICTION:
            raise AttributeError
        return self._property

    @property
    def attribute(self):
        """The attribute the restriction acts on.

        Only for ATTRIBUTE_RESTRICTIONs.

        Raises:
            AttributeError: self is a RELATIONSHIP_RESTRICTIONs.

        Returns:
            UriRef: The datatype of the attribute.
        """
        if self.rtype == RTYPE.RELATIONSHIP_RESTRICTION:
            raise AttributeError
        return self._property

    @property
    def rtype(self):
        """Return the type of restriction.

        Whether the restriction acts on attributes or relationships.

        Returns:
            RTYPE: The type of restriction.
        """
        if self._cached_type is None:
            self._compute_rtype()
        return self._cached_type

    @property
    def _property(self):
        """The relationship or attribute the restriction acts on.

        Returns:
            Union[OntologyRelationship, OntologyAttribute]:
                object of owl:onProperty predicate.
        """
        if self._cached_property is None:
            self._compute_property()
        return self._cached_property

    def _compute_rtype(self):
        """Compute whether this restriction acts on rels or attrs."""
        x = self._property
        if isinstance(x, OntologyRelationship):
            self._cached_type = RTYPE.RELATIONSHIP_RESTRICTION
            return True
        if isinstance(x, OntologyAttribute):
            self._cached_type = RTYPE.ATTRIBUTE_RESTRICTION
            return True

    def _compute_property(self):
        """Compute the object of the OWL:onProperty predicate."""
        x = self._graph.value(self._bnode, rdflib.OWL.onProperty)
        if x and not isinstance(x, BNode):
            self._cached_property = self._namespace_registry.from_iri(x)
            return True

    def _compute_target(self):
        """Compute the target class or datatype."""
        for rdflib_predicate, quantifier in [
            (rdflib.OWL.someValuesFrom, QUANTIFIER.SOME),
            (rdflib.OWL.allValuesFrom, QUANTIFIER.ONLY),
            (rdflib.OWL.cardinality, QUANTIFIER.EXACTLY),
            (rdflib.OWL.minCardinality, QUANTIFIER.MIN),
            (rdflib.OWL.maxCardinality, QUANTIFIER.MAX),
            (rdflib.OWL.hasValue, QUANTIFIER.VALUE),
        ]:
            if self._check_quantifier(rdflib_predicate, quantifier):
                return True

    def _check_quantifier(self, rdflib_predicate, quantifier):
        """Check if the restriction uses given quantifier.

        The quantifier is given as rdflib predicate and python enum.
        """
        x = self._graph.value(self._bnode, rdflib_predicate)
        if x:
            self._cached_quantifier = quantifier
            try:
                self._cached_target = (
                    self._namespace_registry.from_bnode(x)
                    if isinstance(x, BNode)
                    else self._namespace_registry.from_iri(x)
                )
            except KeyError:
                self._cached_target = x
            return True

def get_restriction(bnode, namespace_registry):
    """Return the restriction object represented by given bnode (or None)."""
    r = Restriction(bnode, namespace_registry)
    if r.rtype and r.target:
        return r


from google.appengine.ext import db

class Member(db.Model):
    """The Member model definition.

    Instances of this class simply represent 'people' (presumably) that have
    signed the Fireworks Project Operating Agreement.
    """
    # ### The full name string of the member (first and last).
    member_name = db.StringProperty(required=True)

    # ### The unique identifier for this member.
    # This property is used to make sure that multiple memberships are not
    # created.  The email address of the member is a good value for this
    # property.
    uid = db.StringProperty(required=True)

    # ### The timestamp the member first subscribed.
    init_date = db.IntegerProperty()

class Subscriber(db.Model):
    """The Subscriber model definition.

    Subscriber instances are 'people' (presumably) that have signed up for email
    delivery of one of our subscription services like a blog feed or newsletter.
    """
    # ### The email address of the subscriber
    # This property is required for the subscription.
    email = db.StringProperty(required=True)

    # ### A list of subscriptions the subscriber is subscribed to.
    subscriptions = db.StringListProperty()

    # ### The timestamp the subscriber first subscribed.
    init_date = db.IntegerProperty()

class Browser(db.Model):
    """The Browser model definition.

    Browser instances represent a unique browser that has visited one of our
    pages. It is not a session ID, but a unique identifier associated with the
    user agent. We use a cookie to set the browser ID and ask the browser to
    identify itself on each subsequent request. Obviously user agents that do not
    persist cookies will be recorded as a new browser every time, and will need
    to be filtered.
    """
    # ### The time this entity was created on the server.
    # This property is automatically added when an instance is persisted.
    created = db.DateTimeProperty(auto_now_add=True)

    # ### The formatted user agent string.
    user_agent = db.StringProperty()

    # ### The first page that this browser visited.
    init_path = db.StringProperty()

    # ### The reffering URL that sent this browser here for the first time.
    init_referrer = db.StringProperty()

    # ### The IP address from which this browser came here for the first time.
    init_address = db.StringProperty()

def browser_key(browser):
    """Sanitize or extract a browser keyname for the datastore.

    @param {object|str} browser A Browser datastore instance or a keyname.
    @returns {str} The string repr of the key for the browsers.

    If a str is passed in, it is sanitized for use as a key in the GAE datastore.
    If an object is passed in, we assume it is a Browser instance and extract the
    unsanitized key string from it.
    """
    if isinstance(browser, basestring):
        return 'bid_'+ browser
    key = browser.key()
    key_name = key.name()
    return  key_name and key_name[4:] or str(key)

class Request(db.Model):
    """The Request model definition.

    A Request instance is created every time a client requests a page or
    (optionally) makes an API call.

    Because of client side caching, a request instance is not recorded on every
    page view; but if JS is active on the client, at least one Action instance
    will be recorded for each page view.
    """
    # ### The time this entity was created on the server.
    # This property is automatically added when an instance is persisted.
    created = db.DateTimeProperty(auto_now_add=True)

    # ### The given ID string for this browser.
    browser = db.StringProperty()

    # ### The formatted user agent string.
    user_agent = db.StringProperty()

    # ### The page requested.
    path = db.StringProperty()

    # ### The referring URL of the request.
    referrer = db.StringProperty()

    # ### The IP address of the client that made the request.
    address = db.StringProperty()

    # ### The HTTP status of the request.
    status = db.IntegerProperty()

class Action(db.Model):
    """The Action model definition.

    Instances of this model represent different actions a user may have taken on
    a page. These actions are recorded and sent here by Ajax JS running on the
    page.
    """
    # ### The time this entity was created on the server.
    # This property is automatically added when an instance is persisted.
    created = db.DateTimeProperty(auto_now_add=True)

    # ### The given ID string for this browser.
    browser = db.StringProperty()

    # ### The key string of the last request cookie sent by the server.
    last_request = db.StringProperty()

    # ### The formatted user agent string.
    user_agent = db.StringProperty()

    # ### The current path of the page view.
    path = db.StringProperty()

    # ### The IP address of the client.
    address = db.StringProperty()

    # ### The timestamp of the page load on the client.
    page_time = db.IntegerProperty()

    # ### The client side timestamp of the action.
    timestamp = db.IntegerProperty()

    # ### A description of the action.
    # The description could be anything the client wants to persist. The only
    # restriction is that it must be less than 500 chars.
    description = db.StringProperty()


import pandas as pd
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
from torchvision import transforms
from PIL import Image
from torch.utils.data import DataLoader, TensorDataset

data = pd.read_csv('Brain_Tumor.csv')

# Rename the 'Standard Deviation' column to 'StdDev'
data.rename(columns={'Standard Deviation': 'StdDev'}, inplace=True)

# Separate features and target
X = data[['Mean', 'Variance', 'StdDev', 'Skewness', 'Kurtosis', 'Contrast', 'Energy', 'ASM', 'Entropy', 'Homogeneity', 'Dissimilarity', 'Correlation', 'Coarseness']].values
y = data['Class'].values

X_train, X_temp, y_train, y_temp = train_test_split(X, y, test_size=0.3, random_state=42)
X_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp, test_size=0.5, random_state=42)

class FeatureClassifier(nn.Module):
    def __init__(self, input_size):
        super(FeatureClassifier, self).__init__()
        self.fc1 = nn.Linear(input_size, 64)
        self.fc2 = nn.Linear(64, 1)

    def forward(self, x):
        x = torch.relu(self.fc1(x))
        x = torch.sigmoid(self.fc2(x))
        return x

model = FeatureClassifier(input_size=X_train.shape[1])
criterion = nn.BCELoss()  # Binary Cross-Entropy Loss
optimizer = optim.Adam(model.parameters(), lr=0.001)

def train_model(model, train_loader, val_loader, criterion, optimizer, num_epochs=10):
    """
    Train the machine learning model.

    Args:
        model (nn.Module): The PyTorch model to be trained.
        train_loader (DataLoader): DataLoader for the training dataset.
        val_loader (DataLoader): DataLoader for the validation dataset.
        criterion (nn.Module): Loss function (e.g., CrossEntropyLoss).
        optimizer (optim.Optimizer): Optimization algorithm (e.g., Adam).
        num_epochs (int): Number of training epochs (default: 10).
    """
    for epoch in range(num_epochs):
        model.train()
        # Training loop here
        for inputs, labels in train_loader:
            optimizer.zero_grad()
            outputs = model(inputs)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()

        # Validation after each epoch
        model.eval()
        val_loss = 0.0
        with torch.no_grad():
            for inputs, labels in val_loader:
                outputs = model(inputs)
                val_loss += criterion(outputs, labels)
                # Calculate and log validation metrics here
        val_loss /= len(val_loader)

        print(f'Epoch [{epoch + 1}/{num_epochs}], Validation Loss: {val_loss:.4f}')

        # You can compute additional validation metrics here, e.g., accuracy, precision, recall, F1-score, etc.
        # Example: Compute accuracy
        correct = 0
        total = 0
        with torch.no_grad():
            for inputs, labels in val_loader:
                outputs = model(inputs)
                _, predicted = torch.max(outputs.data, 1)
                total += labels.size(0)
                correct += (predicted == labels).sum().item()

        accuracy = 100 * correct / total
        print(f'Epoch [{epoch + 1}/{num_epochs}], Validation Accuracy: {accuracy:.2f}%')

        # You can add more metrics and logging as needed.

    print('Training finished.')

def validate_model(model, val_loader, criterion):
    """
    Validate the machine learning model.

    Args:
        model (nn.Module): The PyTorch model to be validated.
        val_loader (DataLoader): DataLoader for the validation dataset.
        criterion (nn.Module): Loss function (e.g., CrossEntropyLoss).

    Returns:
        float: Validation loss.
    """
    model.eval()
    val_loss = 0.0
    with torch.no_grad():
        for inputs, labels in val_loader:
            outputs = model(inputs)
            val_loss += criterion(outputs, labels)

        val_loss /= len(val_loader)

    # Calculate and log validation metrics here
    print(f'Validation Loss: {val_loss:.4f}')

    # You can compute additional validation metrics here, e.g., accuracy, precision, recall, F1-score, etc.
    # Example: Compute accuracy
    correct = 0
    total = 0
    with torch.no_grad():
        for inputs, labels in val_loader:
            outputs = model(inputs)
            _, predicted = torch.max(outputs.data, 1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()

    accuracy = 100 * correct / total
    print(f'Validation Accuracy: {accuracy:.2f}%')

    # You can add more metrics and logging as needed.

    return val_loss

def test_model(model, test_loader):
    """
    Test the machine learning model on a test dataset.

    Args:
        model (nn.Module): The PyTorch model to be tested.
        test_loader (DataLoader): DataLoader for the test dataset.

    Returns:
        dict: Dictionary of test metrics (e.g., accuracy, precision, recall).
    """
    model.eval()

    # Initialize variables for computing test metrics
    correct = 0
    total = 0
    all_predicted = []
    all_actual = []

    with torch.no_grad():
        for inputs, labels in test_loader:
            outputs = model(inputs)
            _, predicted = torch.max(outputs.data, 1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()

            all_predicted.extend(predicted.tolist())
            all_actual.extend(labels.tolist())

    accuracy = 100 * correct / total
    # Calculate additional test metrics, e.g., precision, recall, F1-score
    # Example: Calculate precision, recall, and F1-score
    from sklearn.metrics import precision_score, recall_score, f1_score

    precision = precision_score(all_actual, all_predicted)
    recall = recall_score(all_actual, all_predicted)
    f1 = f1_score(all_actual, all_predicted)

    test_metrics = {
        'accuracy': accuracy,
        'precision': precision,
        'recall': recall,
        'f1_score': f1
    }

    print(f'Test Accuracy: {accuracy:.2f}%')
    print(f'Test Precision: {precision:.2f}')
    print(f'Test Recall: {recall:.2f}')
    print(f'Test F1-Score: {f1:.2f}')

    return test_metrics

def save_model(model, path):
    """
    Save the trained model to a file.

    Args:
        model (nn.Module): The PyTorch model to be saved.
        path (str): Path to the file where the model will be saved.
    """
    torch.save(model.state_dict(), path)

def load_model(model, path):
    """
    Load a pre-trained model from a file.

    Args:
        model (nn.Module): The PyTorch model to be loaded.
        path (str): Path to the file where the model is saved.
    """
    model.load_state_dict(torch.load(path))
    model.eval()

def predict_image(model, image_path):
    """
    Make predictions on a single image using the trained model.

    Args:
        model (nn.Module): The PyTorch model for inference.
        image_path (str): Path to the image to be predicted.

    Returns:
        float: Predicted class or probability.
    """
    model.eval()

    # Define image transformations (adjust to match the preprocessing used during training)
    transform = transforms.Compose([
        transforms.Resize((224, 224)),  # Resize image to match model input size
        transforms.ToTensor(),  # Convert image to tensor
        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])  # Normalize image
    ])

    # Load and preprocess the image
    image = Image.open(image_path).convert("RGB")
    image = transform(image).unsqueeze(0)  # Add batch dimension

    # Perform inference
    with torch.no_grad():
        output = model(image)

    # Assuming it's a binary classification (0 for non-tumor, 1 for tumor)
    predicted_class = 1 if output.item() > 0.5 else 0

    return predicted_class

def plot_training_metrics(train_metrics, val_metrics):
    """
    Plot training and validation metrics using Matplotlib.

    Args:
        train_metrics (dict): Training metrics (e.g., loss, accuracy).
        val_metrics (dict): Validation metrics (e.g., loss, accuracy).
    """
    epochs = range(1, len(train_metrics['loss']) + 1)

    # Plot training and validation loss
    plt.figure(figsize=(12, 5))
    plt.subplot(1, 2, 1)
    plt.plot(epochs, train_metrics['loss'], label='Training Loss')
    plt.plot(epochs, val_metrics['loss'], label='Validation Loss')
    plt.title('Training and Validation Loss')
    plt.xlabel('Epochs')
    plt.ylabel('Loss')
    plt.legend()

    # Plot training and validation accuracy
    plt.subplot(1, 2, 2)
    plt.plot(epochs, train_metrics['accuracy'], label='Training Accuracy')
    plt.plot(epochs, val_metrics['accuracy'], label='Validation Accuracy')
    plt.title('Training and Validation Accuracy')
    plt.xlabel('Epochs')
    plt.ylabel('Accuracy')
    plt.legend()

    plt.tight_layout()
    plt.show()

# Assuming you have your training, validation, and test data tensors
train_data_tensor = torch.tensor(X_train, dtype=torch.float32)
train_labels_tensor = torch.tensor(y_train, dtype=torch.float32)

val_data_tensor = torch.tensor(X_val, dtype=torch.float32)
val_labels_tensor = torch.tensor(y_val, dtype=torch.float32)

test_data_tensor = torch.tensor(X_test, dtype=torch.float32)
test_labels_tensor = torch.tensor(y_test, dtype=torch.float32)

# Define batch sizes
batch_size = 32

# Create data loaders
train_dataset = TensorDataset(train_data_tensor, train_labels_tensor)
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)

val_dataset = TensorDataset(val_data_tensor, val_labels_tensor)
val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)

test_dataset = TensorDataset(test_data_tensor, test_labels_tensor)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)

train_model(model, train_loader, val_loader, criterion, optimizer, num_epochs=10)
test_model(model, test_loader)
save_model(model, 'brain_tumor_model.pth')


import nltk
#nltk.download('nps_chat')
#nltk.download('punkt')
posts = nltk.corpus.nps_chat.xml_posts()[:10000]

def show_all():
    print(set(post.get('class') for post in posts))

def dialogue_act_features(post):
    features = {}
    for word in nltk.word_tokenize(post):
        features['contains({})'.format(word.lower())] = True
    return features

def prepare():
    global classifier, dialogue_act_features

    featuresets = [(dialogue_act_features(post.text), post.get('class')) for post in posts]
    size = int(len(featuresets) * 0.1)
    train_set, test_set = featuresets[size:], featuresets[:size]
    classifier = nltk.NaiveBayesClassifier.train(train_set)

def append_punc(raw_text, txt_cls):
    if raw_text[-1] in '.?!':
        return raw_text

    if txt_cls in ['Emphasis', 'yAnswer', 'Statement', 'Clarify', 'nAnswer', 'Continuer', 'Reject', 'System', 'Accept', 'Emotion', 'Other']:
        raw_text += '.'
    elif txt_cls in ['Greet', 'Bye']:
        raw_text += '!'
    elif txt_cls in ['ynQuestion', 'whQuestion']:
        raw_text += '?'

    return raw_text

def infer(raw_text):
    global classifier, dialogue_act_features
    return classifier.classify(dialogue_act_features(raw_text))


import os,sys
import Malt90Source
import aplpy
import gc as garbagecollection
import matplotlib
import pyfits
import malt_params as malt

class AgalSource:
    """
    A class to store information about each ATLASGAL source in MALT90

    Each Agal object has a Malt90 object based on the identification
    made in the linecatalog.

    """

    def __init__(self,atlasgal_id,cat_row,near_lons,near_lats,near_ids):
        self.agal_id = atlasgal_id
        self.agal_name = cat_row['source']
        #self.velocity = float(cat_row['consensus_velocity'])

        self.glon = float(cat_row['ag_long'])
        self.glat = float(cat_row['ag_lat'])

        self.near_lons = near_lons
        self.near_lats = near_lats

        self.awin = 38/60.
        self.bwin = 38/60.

        self.malt90_map = cat_row['malt90_map']
        self.malt90source = Malt90Source.Malt90Source(self.malt90_map,
                                                      self.agal_id)

    def make_herschel_result_images(self):
        try:
            self.malt90source.update_herschel_results()
        except:
        #Hack to deal with files missing Herschel coverage
        #if self.malt90source.atlasgal_mos == "None":
            d,h = pyfits.getdata(self.malt90source.filenames["M24c"],header=True)
            d[:] = 0
            pyfits.writeto(self.malt90source.filenames["RH_T"],d,h,clobber=True)
            pyfits.writeto(self.malt90source.filenames["RH_N"],d,h,clobber=True)

        #try:
        #    self.malt90source.update_atlasgal()
        #except ValueError:
        #Hack to deal with files missing ATLASGAL coverage
        #if self.malt90source.atlasgal_mos == "None":
        #    d,h = pyfits.getdata(self.malt90source.filenames["M24c"],header=True)
        #    d[:] = 0
        #    pyfits.writeto(self.malt90source.filenames["Agal"],d,h,clobber=True)

        Tim,Nim = self.malt90source.get_herschel_result_images()

        images = ["RH_Tim","RH_Nim"]

        #Add ATLASGAL-specific info
        for im,name in zip([Tim,Nim],images):

            im.show_markers(self.near_lons,self.near_lats,edgecolor='blue',facecolor='none',marker='+',s=80,lw=1)
            im.show_markers(self.glon,self.glat,edgecolor='red',facecolor='none',marker='+',s=80,lw=1)
            im.show_ellipses(self.glon,self.glat,0.01,0.01,angle=0,facecolor='none',edgecolor='green',lw=2)
            out_filename = malt.image_dir+self.agal_id+"_"+name+".png"
            im.save(out_filename)
            print("Saving to: "+out_filename)
            im.close()
        matplotlib.pyplot.clf()
        matplotlib.pyplot.close()
        matplotlib.pyplot.close()

        matplotlib.pyplot.close()

        garbagecollection.collect()

    def make_classification_images(self):
        #This checks the database, so is not wasteful
        self.malt90source.update_spitzer()
        #try:
        self.malt90source.update_atlasgal()
        #except ValueError:
        #Hack to deal with files missing ATLASGAL coverage
        #if self.malt90source.atlasgal_mos == "None":
        ##    print("Failed to update ATLASGAL")
        #    d,h = pyfits.getdata(self.malt90source.filenames["M24c"],header=True)
        #    d[:] = 0
        #    pyfits.writeto(self.malt90source.filenames["Agal"],d,h,clobber=True)

        #This returns references to each of the images
        Mim,Gim,Aim = self.malt90source.get_classification_images()
        images = ["Mim","Gim","Aim"]

        #Add ATLASGAL-specific info
        for im,name in zip([Mim,Gim,Aim],images):

            im.show_markers(self.near_lons,self.near_lats,edgecolor='blue',facecolor='none',marker='+',s=80,lw=1)
            im.show_markers(self.glon,self.glat,edgecolor='red',facecolor='none',marker='+',s=80,lw=1)
            im.show_ellipses(self.glon,self.glat,0.01,0.01,angle=0,facecolor='none',edgecolor='green',lw=2)
            out_filename = malt.image_dir+self.agal_id+"_"+name+".png"
            im.save(out_filename)
            print("Saving to: "+out_filename)
            im.close()
        matplotlib.pyplot.clf()
        matplotlib.pyplot.close()
        matplotlib.pyplot.close()

        matplotlib.pyplot.close()

        garbagecollection.collect()


import pandas as pd
import scipy.stats as st
import numpy as np
import matplotlib.pyplot as plt
import os

font = {"size": 18}

results = pd.read_csv("results.csv")
# results = results[results["sample_rate(Hz)"].isin(
#    (24000, 12000, 6000, 3000, 1500, 750, 375))]

sample_rate_means = results.groupby("sample_rate(Hz)").mean(numeric_only=True)

sample_rate_stds = results.groupby("sample_rate(Hz)").std(numeric_only=True)

bit_width_results = results[~results["bit_width"].isin([0])]

bit_width_means = bit_width_results.groupby(
    "bit_width").mean(numeric_only=True)

bit_width_stds = bit_width_results.groupby("bit_width").std(numeric_only=True)

data_type_results = results[results["bit_width"].isin([0])]

data_type_means = data_type_results.groupby(
    "data_type").mean(numeric_only=True)

data_type_stds = data_type_results.groupby("data_type").std(numeric_only=True)

with open("processed-results.txt", "w") as file:
    file.write(
        f"Sample Rate Means:\n{str(sample_rate_means)}\nSample Rate Standard Deviations:\n{str(sample_rate_stds)}\nBit Width Means:\n{str(bit_width_means)}\nBit Width Standard Deviations:\n{str(bit_width_stds)}\nData Type Means:\n{str(data_type_means)}\nData Type Standard Deviations:\n{str(data_type_stds)}")

# Plot the decreasing means
if not os.path.exists("./figures/"):
    os.makedirs("./figures/")

# AUC ROC score plot:
sample_rate_auc_means = sample_rate_means["auc_score"]
bit_width_auc_means = bit_width_means["auc_score"]
bit_width_auc_means = bit_width_auc_means.reindex(["float64", "float32", "int32",
                                                   "int16", "int14", "int12", "int10", "int8", "int6", "int4", "int2"])
data_type_auc_means = data_type_means["auc_score"]

plt.close("all")
figure, ax = plt.subplots()
ax.plot(sample_rate_auc_means.index, sample_rate_auc_means, marker="o")
ax.set_xlim(25000, -2000)
ax.set_ylim(0.45, 1.05)
ax.set_xlabel("Sample Rate (Hz)", fontdict=font)
ax.set_ylabel("ROC AUC Score", fontdict=font)
ax.grid()
for i, label in enumerate(sample_rate_auc_means.index.to_numpy()):
    plt.annotate(label, (sample_rate_auc_means.index.to_numpy()[
                 i]-500, sample_rate_auc_means.to_numpy()[i]+0.01), fontsize="large")
plt.savefig("figures/sample_rate_auc_score.png", format="png")

# Inference time plot:
inference_means = sample_rate_means["inference_time(seconds)"]

plt.close("all")
figure, ax = plt.subplots()
ax.plot(inference_means.index, inference_means, marker="o")
ax.set_xlim(25000, -2000)
ax.set_xlabel("Sample Rate (Hz)", fontdict=font)
ax.set_ylabel("Inference Time (s)", fontdict=font)
ax.grid()
for i, label in enumerate(inference_means.index.to_numpy()):
    if i == 1:
        continue  # To not have overlapping labels
    plt.annotate(label, (inference_means.index.to_numpy()[
                 i]-500, inference_means.to_numpy()[i]+0.01), fontsize="large")
plt.savefig("figures/inference_time.png", format="png")

# Bit Width AUC plot
plt.close("all")
figure, ax = plt.subplots()
ax.plot(bit_width_auc_means.index, bit_width_auc_means, marker="o")
plt.xticks(rotation=45)
ax.set_ylim(0.975, 1.001)
ax.set_xlabel("Data Type", fontdict=font)
ax.set_ylabel("ROC AUC Score", fontdict=font)
ax.grid()
plt.savefig("figures/bit_width_auc_score.pdf", format="pdf")


'''
Handles transactions and stores
'''

import constants

import pathlib
import logging
from glob import glob
import datetime

class transaction:
    value = 0
    description = ""
    category = ""
    subcategory = ""
    date = datetime.datetime.timestamp(datetime.datetime.now())

    def __init__(self, v, d, c, sc, da):
        self.value = float(v)
        self.description = d
        self.category = c
        self.subcategory = sc
        self.date = date = datetime.datetime.utcfromtimestamp(float(da))

transactions = []
transactionsCached = False

def cacheTransactions(storePath) -> bool:
    with open(storePath) as f:
        isFirstline = True
        for line in f:
            if isFirstline:
                isFirstline = False
                continue
            d = readTransaction(line)
            transactions.append(transaction(d["value"], d["description"], d["category"], d["subcategory"], d["timestamp"]))

    return True

def newFinance(filename, directory=None) -> str:
    '''
    Create new finance store
    Returns path to store
    '''
    storeLocation = ""

    if directory != None:
        storeLocation = directory
    else:
        storeLocation = constants.pynanceHomeDir
        makeHomeDir()

    fullpath = storeLocation + "/" + filename + ".csv"

    logging.info("Creating new finance store: " + fullpath)
    with open(fullpath, "w+") as f:
        f.writelines(constants.csvTransactionHeader)

    return fullpath

def makeHomeDir() -> None:
    '''
    Checks if the data directory for pynance already exists in the user's home directory
    '''
    pathlib.Path(constants.pynanceHomeDir).mkdir(parents=True, exist_ok=True)

def checkFinanceStoresInHomeDir() -> list:
    '''
    Returns array of found finance stores in the home directory
    '''
    return glob(constants.pynanceHomeDir + "/*" + ".csv")

def getFinanceName(path) -> str:
    '''
    Returns only the filename of the given path
    '''
    s = path.split('/')
    return s[-1]

def getBalance(storePath) -> float:
    '''
    Checks the account balance of the given finance store
    '''

    global transactionsCached
    if not transactionsCached:
        transactionsCached = cacheTransactions(storePath)

    balance = 0

    for t in transactions:
        balance += t.value

    return balance

def getMonthlyBalance(storePath) -> float:
    global transactionsCached
    if not transactionsCached:
        print("not")
        transactionsCached = cacheTransactions(storePath)

    balance = 0

    currYear = datetime.datetime.now().year
    currMonth = datetime.datetime.now().month

    for t in transactions:
        if t.date.month == currMonth and t.date.year == currYear:
            balance += t.value

    return balance

def readTransaction(transactionString) -> dict:
    '''
    Returns the values of the transaction into a dictionary
    '''

    headers = constants.getCSVHeaders()
    values = transactionString.split(',')
    d = dict()
    for keyindex in range(0, len(headers)):
        d[headers[keyindex]] = values[keyindex]

    return d

def addTransaction(value, description, category, subcategory, timestamp, store) -> bool:
    '''
    Adds the new transaction to the given account. Returns value indicates success.
    '''

    global transactionsCached
    if not transactionsCached:
        transactionsCached = cacheTransactions(storePath)

    logging.info("Adding new transaction: ", value, description, category, subcategory, timestamp, store)

    with open(store, 'w') as f:
        f.writelines(value + ',' + description + ',' + category + ',' + subcategory + ',' + str(timestamp))

    transactions.append(transaction(value, description, category, subcategory, timestamp))

    return True

def getTransactionsList(storePath) -> list:
    global transactionsCached
    if not transactionsCached:
        transactionsCached = cacheTransactions(storePath)

    return transactions


from flask import g, jsonify, redirect, request, Response, abort
import pandas as pd
import json
from dateutil.parser import parse, ParserError

from .models import StationMap
from . import app

@app.errorhandler(400)
def custom400(error):
    response = jsonify({'message': error.description['message']})
    response.status_code = 400
    return response

@app.route("/healthz")
def healthz():
    return jsonify(success=True)

@app.route("/v1/locations")
def list_location():
    """Endpoint returning a list of Station
    ---
    responses:
      200:
        examples:
          ["Jurong East","Bukit Batok","Bukit Gombak","Choa Chu Kang"]
    """
    return jsonify(app.config['station_map'].get_location_list())

@app.route("/v1/route",methods=['POST'])
def find_route():
    """Endpoint returning route from source to destination
    ---
    parameters:
      - name: source
        in: formData
        type: string
        required: true
      - name: destination
        in: formData
        type: string
        required: true
    responses:
      200:
        description: route from source to destination
    """
    source = request.form.get('source')
    destination = request.form.get('destination')
    if not source or not destination:
        abort(400, {'message': 'Missing variables'})
    if len(app.config['station_map'].filter_by_station_name(source))==0:
        abort(404)
    if len(app.config['station_map'].filter_by_station_name(destination))==0:
        abort(404)
    route = app.config['station_map'].find_route_by_station_name(source, destination)
    result = {'number_station':len(route), 'route':route,'instruction':app.config['station_map'].get_instruction_from_route(route)}
    return jsonify(result)

@app.route("/v1/route/time",methods=['POST'])
def find_route_time_constraint():
    """Endpoint returning route from source to destination with time constraint
    ---
    parameters:
      - name: source
        in: formData
        type: string
        required: true
      - name: destination
        in: formData
        type: string
        required: true
      - name: start_time
        in: formData
        type: string
        required: true
    responses:
      200:
        description: route from source to destination
    """
    source = request.form.get('source')
    destination = request.form.get('destination')
    start_time = request.form.get('start_time')
    if not source or not destination or not start_time:
        abort(400, {'message': 'Missing variables'})
    if len(app.config['station_map'].filter_by_station_name(source))==0:
        abort(404)
    if len(app.config['station_map'].filter_by_station_name(destination))==0:
        abort(404)
    try:
      time_obj = parse(start_time)
    except (ParserError, TypeError, OverflowError) as e:
      abort(400, {'message': 'Startime: Wrong datetime format. It should be yyyy-mm-ddTHH:MM:SS+TZ or yyyy-mm-ddTHH:MM'})
    route, time = app.config['station_map'].find_route_with_time_constraint(source, destination, time_obj)
    if route is None:
      return jsonify({'time':time, 'route':[],
        'instruction':['Cannot find any path from given source and destination, some stations are not operation now']})
    result = {'time':time, 'number_station':len(route), 'route':route,'instruction':app.config['station_map'].get_instruction_from_route(route)}
    return jsonify(result)

if __name__ == '__main__':
    app.run(host="0.0.0.0",debug=True, port=8050)


# pylint: disable=unused-argument,invalid-name,line-too-long

from typing import Generator

from sqlalchemy import text as sql_text
from sqlalchemy.sql.elements import TextClause

from alembic_utils.replaceable_entity import ReplaceableEntity
from alembic_utils.statement import coerce_to_unquoted, normalize_whitespace

class PGExtension(ReplaceableEntity):
    """A PostgreSQL Extension compatible with `alembic revision --autogenerate`

    **Parameters:**

    * **schema** - *str*: A SQL schema name
    * **signature** - *str*: A PostgreSQL extension's name
    """

    type_ = "extension"

    def __init__(self, schema: str, signature: str):
        self.schema: str = coerce_to_unquoted(normalize_whitespace(schema))
        self.signature: str = coerce_to_unquoted(normalize_whitespace(signature))
        # Include schema in definition since extensions can only exist once per
        # database and we want to detect schema changes and emit alter schema
        self.definition: str = f"{self.__class__.__name__}: {self.schema} {self.signature}"

    def to_sql_statement_create(self) -> TextClause:
        """Generates a SQL "create extension" statement"""
        return sql_text(f'CREATE EXTENSION "{self.signature}" WITH SCHEMA {self.literal_schema};')

    def to_sql_statement_drop(self, cascade=False) -> TextClause:
        """Generates a SQL "drop extension" statement"""
        cascade = "CASCADE" if cascade else ""
        return sql_text(f'DROP EXTENSION "{self.signature}" {cascade}')

    def to_sql_statement_create_or_replace(self) -> Generator[TextClause, None, None]:
        """Generates SQL equivalent to "create or replace" statement"""
        raise NotImplementedError()

    @property
    def identity(self) -> str:
        """A string that consistently and globally identifies an extension"""
        # Extensions may only be installed once per db, schema is not a
        # component of identity
        return f"{self.__class__.__name__}: {self.signature}"

    def render_self_for_migration(self, omit_definition=False) -> str:
        """Render a string that is valid python code to reconstruct self in a migration"""
        var_name = self.to_variable_name()
        class_name = self.__class__.__name__

        return f"""{var_name} = {class_name}(
    schema="{self.schema}",
    signature="{self.signature}"
)\n"""

    @classmethod
    def from_database(cls, sess, schema):
        """Get a list of all extensions defined in the db"""
        sql = sql_text(
            f"""
        select
            np.nspname schema_name,
            ext.extname extension_name
        from
            pg_extension ext
            join pg_namespace np
                on ext.extnamespace = np.oid
        where
            np.nspname not in ('pg_catalog')
            and np.nspname like :schema;
        """
        )
        rows = sess.execute(sql, {"schema": schema}).fetchall()
        db_exts = [cls(x[0], x[1]) for x in rows]
        return db_exts


import requests    #this is for getting the webpage
from bs4 import BeautifulSoup    #html parser or whatever
import re
import string
import numpy as np

'''
This is our job description scraping file
It goes through every id in 'id_list.txt' and save the text description as a numpy array of strings

Input: .txt File
Output: .txt Files
'''

headers = requests.utils.default_headers()    #need to provide a user-agent code to access the website
headers.update({'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36',})

with open('id_list.txt', 'r')as f:
    job_list = f.readlines()

job_list = list(set(job_list))

# Map the languages with punctuations to letters only
punctuatedLanguages = {"asp.net" : "aspdotnet",
    "f#" : "fsharp",
    "objective-c" : "objectivec",
    "objective-c++" : "objectivecplusplus",
    "c#": "csharp",
    "c++": "cplusplus",
    }

start = 0
end = 12285
# for i in range(end, start, -1): ## this one runs backward
for i in range(start, end):  #this one runs forward
    job_id = job_list[i].replace('\n', '')
    jobPage0 = 'https://www.glassdoor.com/Job/json/details.htm?jobListingId=' + job_id
    jobPage0 = requests.get(jobPage0,headers = headers)
    jobsoup  = BeautifulSoup(jobPage0.text,'html.parser')
    jobsoup = str(jobsoup).lower()
    for element in punctuatedLanguages:
        jobsoup = jobsoup.replace(element, punctuatedLanguages[element])
    jobsoup = re.sub('[%s]'%string.punctuation, " ", jobsoup)
    jobsoup = jobsoup.split()
    np.save('job_description' + str(i) + '.npy', jobsoup)   # Save each job description as a numpy file
    print(i)


###############################################
#
# Author: John Gordley
# Professor: Aniruddha Gokhale
# Vanderbilt University
#
# Purpose: Simple publisher script that comes and goes and does not perform is_ready
#
# Created: Spring 2023
#
###############################################

# import the needed packages
import time   # for sleep
import argparse  # for argument parsing
import configparser  # for configuration parsing
import logging  # for logging. Use it in place of print statements.
import random  # needed in the topic selection using random numbers
import sys
import atexit

# Import our topic selector. Feel free to use alternate way to
# get your topics of interest
from topic_selector import TopicSelector

# Now import our CS6381 Middleware
from CS6381_MW.ActivePublisherMW import PublisherMW

# import any other packages you need.

##################################
#       PublisherAppln class
##################################

class PublisherAppln ():

    ########################################
    # constructor
    ########################################
    def __init__(self, logger):
        self.iters = None   # number of iterations of publication
        self.name = None  # our name (some unique name)
        self.topiclist = None  # the different topics that we publish on
        self.lookup = None  # one of the diff ways we do lookup
        self.dissemination = None  # direct or via broker
        self.mw_obj = None  # handle to the underlying Middleware object
        self.logger = logger  # internal logger for print statements
        self.num_topics = None  # number of topics we want to publish

    ########################################
    # configure/initialize
    ########################################
    def configure(self, args):
        ''' Initialize the object '''

        try:
            # Here we initialize any internal variables
            self.logger.debug("PublisherAppln::configure")

            # initialize our variables
            self.name = args.name  # our name
            self.iters = args.iters  # num of iterations
            self.num_topics = args.num_topics

            # Now, get the configuration object
            self.logger.debug("PublisherAppln::configure - parsing config.ini")
            config = configparser.ConfigParser()
            config.read(args.config)
            self.lookup = config["Discovery"]["Strategy"]
            self.dissemination = config["Dissemination"]["Strategy"]

            # Now get our topic list of interest
            self.logger.debug("PublisherAppln::configure - selecting our topic list")
            ts = TopicSelector()
            self.topiclist = ts.interest(self.num_topics)

            # Now setup up our underlying middleware object to which we delegate
            # everything
            self.mw_obj = PublisherMW(self.logger, self.num_topics, self.lookup)

            # pass remainder of the args to the m/w object
            self.mw_obj.configure(args)

            atexit.register(self.mw_obj.clean_exit, self.name)

            self.logger.info(f"PublisherAppln - {self.name} configured with topics: {self.topiclist}")

        except Exception as e:
            raise e

    ########################################
    # driver program
    ########################################
    def driver(self):
        ''' Driver program '''

        try:
            self.logger.debug("PublisherAppln::driver")

            # dump our contents (debugging purposes)
            self.dump()

            # First ask our middleware to register ourselves with the discovery service
            self.logger.info(f"PublisherAppln - Attempting to register with Discovery service")
            result = self.mw_obj.register(self.name, self.topiclist)
            self.logger.info(f"PublisherAppln - Result of registration: {result}")
            if result != '1':
                self.logger.info(f"PublisherAppln - Failed to register. Exiting...")
                sys.exit(1)

            time.sleep(10)

            # Now disseminate
            ts = TopicSelector()
            for i in range(self.iters):
                # I leave it to you whether you want to disseminate all the topics of interest in
                # each iteration OR some subset of it. Please modify the logic accordingly.
                # Here, we choose to disseminate on all topics that we publish.  Also, we don't care
                # about their values. But in future assignments, this can change.
                for topic in self.topiclist:
                    # dissemination_data = topic + ":" + ts.gen_publication (topic)

                    self.mw_obj.disseminate(topic, ts.gen_publication(topic))

                    # time.sleep(random.randrange(1, 5))
                    time.sleep(2)

            self.logger.info(f"PublisherAppln - Dissemination complete after {self.iters} rounds")

            # Gracefully exit
            self.mw_obj.clean_exit(self.name)

        except Exception as e:
            raise e

    ########################################
    # dump the contents of the object
    ########################################
    def dump(self):
        ''' Pretty print '''

        try:
            self.logger.debug("**********************************")
            self.logger.debug("PublisherAppln::dump")
            self.logger.debug("------------------------------")
            self.logger.debug("     Name: {}".format(self.name))
            self.logger.debug("     Lookup: {}".format(self.lookup))
            self.logger.debug(
                "     Dissemination: {}".format(self.dissemination))
            self.logger.debug("     TopicList: {}".format(self.topiclist))
            self.logger.debug("     Iterations: {}".format(self.iters))
            self.logger.debug("**********************************")

        except Exception as e:
            raise e

###################################
#
# Parse command line arguments
#
###################################

def parseCmdLineArgs():
    # instantiate a ArgumentParser object
    parser = argparse.ArgumentParser(description="Publisher Application")

    # Now specify all the optional arguments we support
    # At a minimum, you will need a way to specify the IP and port of the lookup
    # service, the role we are playing, what dissemination approach are we
    # using, what is our endpoint (i.e., port where we are going to bind at the
    # ZMQ level)

    parser.add_argument("-n", "--name", required=True, default="pub",
                        help="Some name assigned to us. Keep it unique per publisher")

    parser.add_argument("-a", "--addr", required=True, default="localhost",
                        help="IP addr of this publisher to advertise (default: localhost)")

    parser.add_argument("-p", "--port", default="5577",
                        help="Port number on which our underlying publisher ZMQ service runs, default=5577")

    parser.add_argument("-d", "--discovery", required=True, default="localhost:5555",
                        help="IP Addr:Port combo for the discovery service, default localhost:5555")

    parser.add_argument("-t", "--num_topics", type=int, choices=range(1,
                        10), default=1, help="number of topics to select")

    parser.add_argument("-c", "--config", default="config.ini",
                        help="configuration file (default: config.ini)")

    parser.add_argument("-i", "--iters", type=int, default=1000,
                        help="number of publication iterations (default: 1000)")

    parser.add_argument("-l", "--loglevel", type=int, default=logging.INFO, choices=[
                        logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL], help="logging level, choices 10,20,30,40,50: default 10=logging.DEBUG")

    return parser.parse_args()

###################################
#
# Main program
#
###################################
def main():

    # obtain a system wide logger and initialize it to debug level to begin with
    logging.debug(
        "Main - acquire a child logger and then log messages in the child")
    logger = logging.getLogger("PubAppln")

    # first parse the arguments
    logger.debug("Main: parse command line arguments")
    args = parseCmdLineArgs()

    # reset the log level to as specified
    logger.debug("Main: resetting log level to {}".format(args.loglevel))
    logger.setLevel(args.loglevel)
    logger.debug("Main: effective log level is {}".format(
        logger.getEffectiveLevel()))

    # Obtain a publisher application
    logger.debug("Main: obtain the object")
    pub_app = PublisherAppln(logger)

    # configure the object
    pub_app.configure(args)

    # now invoke the driver program
    pub_app.driver()

###################################
#
# Main entry point
#
###################################
if __name__ == "__main__":

    # set underlying default logging capabilities
    logging.basicConfig(level=logging.INFO,
                        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')

    main()


from app.models.schema import ImportDevicesOut
from app.services.auth import get_admin_active_user, get_manager_active_user
from app.services.migration import (
    import_devices,
    import_workshop_events,
    import_factory_worker_infos,
)
from fastapi import APIRouter, Depends, File, Response, UploadFile, Form
from app.core.database import AuditActionEnum, User, AuditLogHeader
from fastapi.exceptions import HTTPException
from typing import List

router = APIRouter(prefix="/migration")

@router.post("/devices", tags=["migration"], status_code=201, response_model=ImportDevicesOut)
async def import_devices_from_excel(
    file: UploadFile = File(...),
    user: User = Depends(get_manager_active_user),
):
    if file.filename.split(".")[1] != "xlsx":
        raise HTTPException(415)

    try:
        device_ids, params = await import_devices(file)
        await AuditLogHeader.objects.create(
            table_name="devices",
            action=AuditActionEnum.DATA_IMPORT_SUCCEEDED.value,
            user=user,
        )
        return ImportDevicesOut(device_ids=device_ids, parameter=params.to_csv())
    except Exception as e:
        await AuditLogHeader.objects.create(
            table_name="devices",
            action=AuditActionEnum.DATA_IMPORT_FAILED.value,
            user=user,
            description="Import devices layout failed",
        )
        raise HTTPException(status_code=400, detail=repr(e))

@router.post("/workshop-eventbook", tags=["migration"], status_code=201,
    responses={
        201: {
            "content": {"image/csv": {}},
            "description": "Return parameters in csv format",
        },
        400: {"description": "There's is an error in your document."},
        415: {"description": "The file you uploaded is not in correct format.",},
    }
)
async def import_workshop_eventbooks_from_excel(
    file: UploadFile = File(...),
    # clear_all: bool = Form(default=False),
    user: User = Depends(get_manager_active_user),
):
    if file.filename.split(".")[1] != "xlsx" and file.filename.split(".")[1] != "xls":
        raise HTTPException(415)

    try:
        params = await import_workshop_events(file)
        return Response(
            content=params.to_csv(),
            status_code=201,
            media_type='text/csv'
        )
    except Exception as e:
        await AuditLogHeader.objects.create(
            table_name="categorypris",
            action=AuditActionEnum.DATA_IMPORT_FAILED.value,
            user=user,
            description="Import workshop eventbooks failed",
        )
        raise HTTPException(status_code=400, detail=repr(e))

@router.post("/factory-worker-infos", tags=["migration"], status_code=201,
    responses={
        201: {
            "content": {"image/csv": {}},
            "description": "Return parameters in csv format",
        },
        400: {"description": "There's is an error in your document."},
        415: {"description": "The file you uploaded is not in correct format.",},
    }
)
async def import_factory_worker_infos_from_excel(
    workshop_name: str = Form(default="第九車間", description="要匯入員工資訊的車間名稱"),
    file: UploadFile = File(...),
    user: User = Depends(get_manager_active_user),
):
    if file.filename.split(".")[1] != "xlsx":
        raise HTTPException(415)

    try:
        params = await import_factory_worker_infos(workshop_name, file)
        await AuditLogHeader.objects.create(
            table_name="users",
            action=AuditActionEnum.DATA_IMPORT_SUCCEEDED.value,
            user=user,
        )

        return Response(
            content=params.to_csv(),
            status_code=201,
            media_type='text/csv'
        )
    except Exception as e:
        await AuditLogHeader.objects.create(
            table_name="users",
            action=AuditActionEnum.DATA_IMPORT_FAILED.value,
            user=user,
        )
        raise e


import numpy
import math
import arcade

# --- Set up the constants

# Size of the screen
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 600
SCREEN_TITLE = "Bouncing Rectangle Example"

# Size of the rectangle
RECT_WIDTH = 50
RECT_HEIGHT = 50

age_range =             [20, 40, 60, 80]
#questo è ok
Speed_range =           [1.5, 1.8, 2.1, 2.4, 2.7, 3.0]
#questo è ok
μ_global_range =        [0.1, 0.8]
#questo è ok
reaction_time_range =   [1.5, 3.0, 4.5]
#questo è fisso
fixed_value =           250

age = numpy.random.choice(
#questo è ok
age_range, p=[0.22, 0.54, 0.10, 0.14])
#questo è ok
Speed = numpy.random.choice(
Speed_range, p=[0.05, 0.10, 0.35, 0.35, 0.10, 0.05])
#questo è ok
reaction_time = numpy.random.choice(
reaction_time_range, p=[0.8, 0.18, 0.02])
#questo è ok
μ_value = numpy.random.choice(
μ_global_range, p=[0.01, 0.99])
#questo è ok
skill_factor = 0#fov calculations

if age == 20 or age == 80:
    skill_factor = 0.6
elif age == 40:
    skill_factor = 0.0
elif age == 60:
    skill_factor = 0.2
#print("Skill", skill_factor)

if skill_factor == 0.6:
    R_dist = ((math.pow(Speed, 2.0) *
                    reaction_time)/(3.6 - skill_factor))

#print("R_dist", R_dist)
elif skill_factor == 0.0:
    R_dist = ((math.pow(Speed, 2.0) * reaction_time)/(3.6 + skill_factor))

#print("R_dist", R_dist)
elif skill_factor == 0.2:
    R_dist = ((math.pow(Speed, 2.0) * reaction_time)/(3.6 - skill_factor))
    print("R_dist", R_dist)

B_dist = ((math.pow(Speed, 2.0) /(fixed_value * μ_value)))
print("B_dist",B_dist)

FOV_length = R_dist + B_dist

print(FOV_length)

def on_draw(delta_time):

    arcade.start_render()
    arcade.draw_line(270,0,270,600, arcade.color.WINE)
    arcade.draw_line(330,0,330,600, arcade.color.WINE)
    hitbox_list = arcade.SpriteList()
    car_list = arcade.SpriteList()
    car = arcade.Sprite("../Concept Art/Blocks/car.png", 1, center_x=300, center_y=300)
    hitbox = arcade.Sprite("../Concept Art/hitbox.png", FOV_length, center_x=300, center_y=300)
    hitbox_list.append(hitbox)
    hitbox_list.draw()

def main():
    arcade.open_window(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
    arcade.set_background_color(arcade.color.WHITE)

    # Tell the computer to call the draw command at the specified interval.
    arcade.schedule(on_draw, 1 / 80)

    # Run the program
    arcade.run()

if __name__ == "__main__":
    main()


##############################################################
#### Written By: ANKHI PAUL                               ####
#### Written On: 03-MAR-2020                              ####
#### Modified On 03-MAR-2020                              ####
#### Objective: AWS Lambda script written in Python       ####
####                 to read csv file from S3             ####
##############################################################

import boto3
s3 =  boto3.client('s3') #boto3 is Python SDK for AWS
URL = "https://maps.googleapis.com/maps/api/geocode/json"
key = config.api_key
bucket = 'pythonusecase'

def lambda_handler(event, context):
    # Reading file into dictionary - https://stackoverflow.com/questions/42312196/how-do-i-read-a-csv-stored-in-s3-with-csv-dictreader
    csvfile=s3.get_object(Bucket=bucket, Key='employee_demo.txt')
    csvfile = csv.DictReader(codecs.getreader('utf-8')(csvfile[u'Body']))

    # In memory file writing
    csvio = io.StringIO()
    writer = csv.DictWriter(csvio, fieldnames=["Name", "Address_line_1", "Postal_Code"])
    writer.writeheader()

    for row in csvfile:
        print(row)
        # defining a params dict for the parameters to be sent to the API
        PARAMS = {'address': row['Address_line_1'],'key': key}
        # sending get request and saving the response as response object
        r = requests.get(url=URL, params=PARAMS)

        # extracting data in json format
        output = r.json()
        correct_postal_code = output['results'][0]['address_components'][7]['long_name']
        print('Correct postal code:'+correct_postal_code)
        row['Postal_Code'] = correct_postal_code
        writer.writerow(row)
    print('============Put output file into s3 =========')
    #s3 - https://stackoverflow.com/questions/57768041/how-do-i-use-aws-lambda-to-create-csv-file-from-json-data
    s3.put_object(Body=csvio.getvalue(), ContentType='text/csv', Bucket=bucket, Key='employee_demo_out.txt')
    csvio.close()

    return {
        'statusCode': 200,
        'message': 'Success'
    }