#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
.. $Id$
"""

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

from zope import interface

from zope.schema.vocabulary import SimpleTerm
from zope.schema.vocabulary import SimpleVocabulary

from nti.schema.field import Bool
from nti.schema.field import List
from nti.schema.field import Text
from nti.schema.field import Choice
from nti.schema.field import Number
from nti.schema.field import Object
from nti.schema.field import HTTPURL
from nti.schema.field import DateTime
from nti.schema.field import TextLine
from nti.schema.field import ValidURI

class IRevClient(interface.Interface):
    """
    Handles Rev order operations.
    """

    def __init__(authorization):
        """
        Args:
            authorization (:obj:`IAuthorization`): The client and user API keys.

        """

    def upload_source_file(source_file_upload):
        """
        Upload an ISourceFileUpload to create a new ISourceFileInput to be used in an order.

        Args:
            source_file_upload (:obj:`ISourceFileUpload`): The source file to upload to be used in an order.

        Returns:
            (:obj:`ISourceFileInput`): The newly uploaded source file to be used in an order.

        Raises:
            UnsupportedContentType: If the content type of the media is not currently supported by Rev system.
            CouldNotRetrieveFile: If Rev could not retrieve the file from the specified location.
            InvalidMultipartRequest: If the multipart request did not contain exactly one file part or was otherwise malformed.
            UnspecifiedFilename: If the filename for the media was not specified explicitly and could not be determined automatically.
            UnspecifiedURL: If the URL for the media was not specified.

        """

    def submit_transcription_order(transcription_order_request):
        """
        Submit a new ITranscriptionOrder given an ITranscriptionOrderRequest.

        Args:
            transcription_order_request (:obj:`ITranscriptionOrderRequest`): The order request for a new transcription order.

        Returns:
            (:obj:`ITranscriptionOrder`): The newly created transcription order.

        Raises:
            MissingInputs: If the order request did not contain any input media.
            InvalidInput: If one of the input media URIs is invalid (e.g. does not identify valid uploaded media).
            MultipleServiceOptionsSpecified: If both transcription options and caption options are included in the request.
                Currently, an order can be made for only one of the two services Rev offers (transcription or caption).
            ServiceTypeNotSpecified: If transcription options for order are not specified.
            ExternalLinkAndURISpecified: If both external link and URI are set for input media.
            InputLocationNotSpecified: If neither external link or URI are set for input media.
            CannotConnectToExternalLink: If Rev cannot connect to external link provided.
            InvalidMediaLength: If input media length is not provided and Rev is unable to calculate it automatically
                or if input media length is not a positive integer.
            ReferenceNumberTooLong: If the reference number provided is longer than 256 characters.
            IneligibleForBalancePayments: If the user on whose behalf the order request was made is not eligible for paying using account balance.
            AccountBalanceLimitExceeded: If the order request specified payment using account balance but doing so would exceed the user's balance limit.
            FieldValidationErrors: If one or more of the fields are in the wrong format.

        """

    def submit_caption_order(caption_order_request):
        """
        Submit a new ICaptionOrder given an ICaptionOrderRequest.

        Args:
            caption_order_request (:obj:`ICaptionOrderRequest`): The order request for a new caption order.

        Returns:
            (:obj:`ICaptionOrder`): The newly created caption order.

        Raises:
            MissingInputs: If the order request did not contain any input media.
            InvalidInput: If one of the input media URIs is invalid (e.g. does not identify valid uploaded media).
            MultipleServiceOptionsSpecified: If both transcription options and caption options are included in the request.
                Currently, an order can be made for only one of the two services Rev offers (transcription or caption).
            ServiceTypeNotSpecified: If caption options for order are not specified.
            ExternalLinkAndURISpecified: If both external link and URI are set for input media.
            InputLocationNotSpecified: If neither external link or URI are set for input media.
            CannotConnectToExternalLink: If Rev cannot connect to external link provided.
            InvalidMediaLength: If input media length is not provided and Rev is unable to calculate it automatically
                or if input media length is not a positive integer.
            InvalidLanguageCode: If one or more of the provided language codes are invalid.
            IncompatibleLanguage: If some of the selected output file formats do not support one or more of the specified languages.
                For example, Scenarist (Scc), MacCaptions (Mcc) and CheetahCap (CAP) are incompatible with languages that use non-Latin alphabets.
            ReferenceNumberTooLong: If the reference number provided is longer than 256 characters.
            IneligibleForBalancePayments: If the user on whose behalf the order request was made is not eligible for paying using account balance.
            AccountBalanceLimitExceeded: If the order request specified payment using account balance but doing so would exceed the user's balance limit.
            FieldValidationErrors: If one or more of the fields are in the wrong format.

        """

    def get_order(ordernum):
        """
        Get the IOrder detailed information for the order with the given order number.

        Args:
            ordernum (str): The order number of the order to retrieve.

        Returns:
            (:obj:`IOrder`): The order details for the order with the given order number.

        Raises:
            NotFound: If the order with the given order number is not found or does not belong to the user.

        """

    def get_orders(pagenum=1, pageSize=25, orderNumber=None, referenceId=None):
        """
        Get the paged list IOrders for user, optionally getting orders with specific order number or reference ID.

        Args:
            pagenum (int, optional): The number of the page of orders to return. Defaults to page 1.
            pageSize (int, optional): The number of orders per page to return. Page size must be between 5 and 100.
                Defaults to 25 orders per page.
            orderNumber (str, optional): The order number of the order to retrieve.
                Must not be specified if clientRef is specified.
                Defaults to returning all orders.
            referenceId (str, optional): The reference ID as used in your application of the order to retrieve.
                Must not be specified if orderNumber is specified.
                Defaults to returning all orders.

        Returns:
            (:obj:`IOrders`): The list of orders for a user returned in a paged manner.
                The returned result will indicate the total number of orders, as well as number of orders per page and
                the number of orders in the requested page, which enables a client to iteratively retrieve all orders for the user if desired.
                The results are ordered in reverse chronological order by placed on date.

                Each order entity in the list contains summary information for the order - it omits comments and attachments.
                To get those, call get_order(ordernum) with the appropriate order number.

        Raises:
            OrderNumberAndReferenceIdSpecified: If both orderNumber and referenceId are specified.

        """

    def cancel_order(ordernum):
        """
        Cancel the IOrder with the given order number.

        Orders can only be cancelled if work on them has not begun yet.

        Args:
            ordernum (str): The order number of the order to be cancelled.

        Returns:
            bool: True if successful, False otherwise.

        Raises:
            NotFound: If the order with the given order number is not found.
            CancelForbidden: If the order cannot be cancelled because work on the order has already begun.

        """

    def get_attachment(attachment_id):
        """
        Get the IAttachment for the given attachment ID.

        Args:
            attachment_id (str): The ID of the attachment to retrieve.

        Returns:
            (:obj:`IAttachment`): The attachment with the given attachment ID.

        Raises:
            NotFound: If the attachment with the given attachment ID is not found.

        """

    def get_attachment_content(attachment_id, file_format):
        """
        Get the IAttachmentContent for the IAttachment with the given ID.

        Use this method to download either finished output file(s)
        (transcripts or captions, depending on the type of order you placed),
        or the source file(s) for an order.

        Args:
            attachment_id (str): The ID of the attachment for which to retrieve its content.
            file_format (str): The requested file format for the attachment content.
                Defaults to Microsoft Word (.docx) for transcripts.
                Defaults to SubRip (.srt) for captions.

        Returns:
            (:obj:`IAttachmentContent`): The content of the attachment with the given ID.

        Raises:
            NotFound: If the attachment with the given attachment ID is not found.
            UnsupportedFileFormat: If none of the requested representations are available for the attachments
                or the file format specified for a source file does not match the original format.

        """

class IClientAPIKey(interface.Interface):
    """
    A secret key specific to each partner that wishes to use the Rev API
    """

    client_API_key = TextLine(title=u'The client API key',
                              description=u"""This is a secret key specific to each partner
                              that wishes to use the Rev API.""",
                              required=True)

class IUserAPIKey(interface.Interface):
    """
    A secret key specific to a Rev user
    """

    user_API_key = TextLine(title=u'The user API key',
                            description=u"""This is a secret key specific to a Rev user,
                            which identifies the user account under whose privileges
                            the requested operation executes.""",
                            required=True)

class IAuthorization(IClientAPIKey, IUserAPIKey):
    """
    Security and authentication keys used to access the Rev API
    """

class ISourceFileUpload(interface.Interface):
    """
    Describes a media source file to be retrieved, uploaded, and used in an order.
    """

    content_type = TextLine(title=u'The content type of the media to be retrieved',
                            description=u"""If not specified, Rev will try to determine the content type
                            from the server response.""",
                            required=False)

    filename = TextLine(title=u'The filename for the media',
                        description=u"""If not specified, Rev will try to determine the filename
                        from the URL.""",
                        required=False)

    url = HTTPURL(title=u'The URL where the media can be retrieved',
                  description=u"""The URL must be publicly accessible.
                  HTTPS URLs are ok as long as the site in question has a valid certificate,""",
                  required=True)

class IInput(interface.Interface):
    """
    An order input file to be captioned or transcribed
    """

class ISourceFileInput(IInput):
    """
    An order input for a source file that has already been uploaded to be used in an order
    """

    audio_length_seconds = Number(title=u'The length of the audio (in seconds, rounded up)',
                                  description=u"""If the URI is for media stored in an S3 bucket,
                                  Rev will try to calculate the audio length automatically.""",
                                  required=False)

    uri = ValidURI(title=u'A URI identifying the uploaded media',
                   required=True)

class IExternalLinkInput(IInput):
    """
    An order input for an external link to a file
    """

    audio_length_seconds = Number(title=u'The length of the audio (in seconds, rounded up)',
                                  description=u"""If external link is a YouTube URL,
                                  audio length is determined automatically.""",
                                  required=False)

    external_link = HTTPURL(title=u'The external link URL',
                            required=True)

class ISpeaker(interface.Interface):
    """
    A speaker
    """

    id = Number(title=u'The ID of the speaker',
                required=True)

    name = TextLine(title=u'The name of the speaker',
                    required=True)

class ISpeakers(interface.Interface):
    """
    The attachment speakers
    """

    speakers = List(value_type=Object(ISpeaker),
                    title=u'A list of speakers',
                    required=True)

MONOLOGUE_ELEMENT_TYPE_TAG = u'tag'
MONOLOGUE_ELEMENT_TYPE_TEXT = u'text'

MONOLOGUE_ELEMENT_TYPE_ITEMS = (MONOLOGUE_ELEMENT_TYPE_TEXT,
                                MONOLOGUE_ELEMENT_TYPE_TAG)

MONOLOGUE_ELEMENT_TYPE_VOCABULARY = SimpleVocabulary(
    [SimpleTerm(_x) for _x in MONOLOGUE_ELEMENT_TYPE_ITEMS]
)

class IMonologueElement(interface.Interface):
    """
    Each element of a monologue is either text (transcribed speech)
    or a tag (an annotation), such as inaudible or crosstalk.
    """

    type = Choice(vocabulary=MONOLOGUE_ELEMENT_TYPE_VOCABULARY,
                  title=u'The type of the monologue element',
                  required=True)

    value = Text(title=u'The value of the monologue element',
                 description=u"""For text elements, value contains the text.
                 For tag elements, value contains the annotation type.""",
                 required=True)

    # FIXME: Required for tag elements but not required for text elements
    timestamp = DateTime(title=u'The timestamp',
                         description=u"""Rev uses timestamp format hh:mm:sss,fff
                         where fff represent milliseconds.
                         Text elements may or may not contain a timestamp.
                         Tag elements require a timestamp.""")

class IMonologueElements(interface.Interface):
    """
    Elements of a monologue.
    """

    elements = List(value_type=Object(IMonologueElement),
                    title=u'A list of monologue elements',
                    required=True)

class IMonologue(interface.Interface):
    """
    A monologue (transcribed speech).
    Each monologue corresponds to a run of text from one speaker.
    """

    id = Number(title=u'The ID of the monologue',
                required=True)

    # FIXME: Indicate speaker must be one of the speakers from the attachment content's ISpeakers
    # This speaker ID is the same as the ISpeaker id
    speaker = Number(title=u'The ID of the speaker',
                     required=True)

    # FIXME: Indicate speaker must be one of the speakers from the attachment content's ISpeakers
    # This speaker_name is the same as the ISpeaker name
    speaker_name = TextLine(title=u'The name of the speaker',
                            required=True)

    elements = Object(schema=IMonologueElements,
                      title=u'Elements of the monologue',
                      required=True)

class IMonologues(interface.Interface):
    """
    The attachment monologues (transcribed speech)
    """

    monologues = List(value_type=Object(IMonologue),
                      title=u'A list of monologues',
                      required=True)

class IComment(interface.Interface):
    """
    A comment on an order
    """

    by = TextLine(title=u'The author of the comment',
                  required=True)

    timestamp = DateTime(title=u'The date and time the comment was made. in UTC',
                         required=True)

    text = Text(title=u'The text of the comment',
                required=True)

NOTIFICATION_FINAL_ONLY = u'(the default) A notification is sent only when the order is complete'
NOTIFICATION_DETAILED = u'A notification is sent whenever the order is in a new status or has a new comment'

NOTIFICATION_ITEMS = (NOTIFICATION_DETAILED,
                      NOTIFICATION_FINAL_ONLY)

NOTIFICATION_VOCABULARY = SimpleVocabulary(
    [SimpleTerm(_x) for _x in NOTIFICATION_ITEMS]
)

class INotification(interface.Interface):
    """
    Options specified when placing a request for an order
    to enable receiving notifications about the order status
    """

    url = HTTPURL(title=u'The URL where updates will be posted',
                  required=True)

    level = Choice(vocabulary=NOTIFICATION_VOCABULARY,
                   title=u'Specifies which notifications are sent',
                   required=False)

# FIXME? nti.interfaces ILinks, might change into NTILinks (leave for now)
class ILink(interface.Interface):
    """
    Link with URL of the resource for getting attachment content
    """

    # Likely, rel="content"
    rel = TextLine(title=u'The relationship between the current document and the linked document',
                   required=True)

    href = TextLine(title=u'The URL of the link',
                    required=True)

class ILinks(interface.Interface):
    """
    Links with URLs of the resource for getting attachment content
    """

    links = List(value_type=Object(ILink),
                 title=u'A list of links with URLs of the resource for getting attachment content',
                 required=True)

ATTACHMENT_KIND_MEDIA = u'media'
ATTACHMENT_KIND_CAPTION = u'caption'
ATTACHMENT_KIND_TRANSCRIPT = u'transcript'

ATTACHMENT_KIND_ITEMS = (ATTACHMENT_KIND_MEDIA,
                         ATTACHMENT_KIND_TRANSCRIPT,
                         ATTACHMENT_KIND_CAPTION)

ATTACHMENT_KIND_VOCABULARY = SimpleVocabulary(
    [SimpleTerm(_x) for _x in ATTACHMENT_KIND_ITEMS]
)

class IAttachment(interface.Interface):
    """
    An attachment

    Attachments are either source files (audio or video for transcriptions orders, videos for caption orders)
    or output files (transcripts or captions, depending on the type of order).
    """

    kind = Choice(vocabulary=ATTACHMENT_KIND_VOCABULARY,
                  title=u'The kind of attachment',
                  required=True)
    # FIXME? "name" is not description, change to "filename?"
    # JSON object uses "name," so leave for now
    name = TextLine(title=u'Filename for the attachment',
                    required=True)

    id = TextLine(title=u'ID for the attachment',
                  required=True)

    # FIXME: Indicate this attribute is only included if kind="transcript"
    audio_length_seconds = Number(title=u'The length (in seconds) of the audio attachment',
                                  required=False)

    links = Object(schema=ILinks,
                   title=u'A list of links with URLs of the resource for getting attachment content',
                   required=True)

class IAttachments(interface.Interface):
    """
    A list of attachments
    """

    attachments = List(value_type=Object(IAttachment),
                       title=u'A list of attachments',
                       required=True)

class IAttachmentContent(interface.Interface):
    """
    The content of the attachment
    """

    speakers = Object(schema=ISpeakers,
                      title=u'The speakers',
                      required=True)

    monologues = Object(schema=IMonologues,
                        title=u'The monologues (transcribed speech)',
                        description=u"""Each monologue corresponds to a run of text from one speaker.""",
                        required=True)

class IOrderRequest(interface.Interface):
    """
    An object providing information for placing an order
    """
    client_ref = TextLine(title=u'A reference number for the order meaningful to the client',
                          required=False)

    notification = Object(schema=INotification,
                          title=u'Enables receiving notifications about the order status',
                          required=False)

#: Completed and Cancelled are the only status values guaranteed not to
#: change in v1 of the API.

ORDER_STATUS_COMPLETED = u'Completed'
ORDER_STATUS_CANCELLED = u'Cancelled'
ORDER_STATUS_CAPTIONING = u'Captioning'
ORDER_STATUS_IN_PROGRESS = u'In Progress'
ORDER_STATUS_TRANSCRIBING = u'Transcribing'

ORDER_STATUS_ITEMS = (ORDER_STATUS_TRANSCRIBING,
                      ORDER_STATUS_CAPTIONING,
                      ORDER_STATUS_IN_PROGRESS,
                      ORDER_STATUS_COMPLETED,
                      ORDER_STATUS_CANCELLED)

ORDER_STATUS_VOCABULARY = SimpleVocabulary(
    [SimpleTerm(_x) for _x in ORDER_STATUS_ITEMS]
)

class IOrderDetails(interface.Interface):
    """
    The details of an order
    """

    order_number = TextLine(title=u'Rev assigned order number',
                            required=True)

    client_ref = TextLine(title=u'The client reference order number provided with the order request',
                          required=True)

    # TODO: Rounded to the nearest whole dollar? Convert to cents?
    # Probably fractional, rounded to two decimal places
    # "The price unit in Dollars and it shows default order price" what does default order price mean?
    price = Number(title=u'Total cost of the order (in dollars)',
                   required=True)

    status = Choice(vocabulary=ORDER_STATUS_VOCABULARY,
                    title=u'The status of the order',
                    required=True)

    attachments = List(value_type=Object(IAttachment),
                       title=u'The attachments with the order',
                       required=True)

    comments = List(value_type=Object(IComment),
                    title=u'The comments on the order',
                    required=True)

class IOrder(IOrderRequest, IOrderDetails):
    """
    An order
    """

class IOrders(interface.Interface):
    """
    A list of orders
    """

    orders = List(value_type=Object(IOrder),
                  title=u'A list of orders',
                  required=True)

class ITranscriptionOptions(interface.Interface):
    """
    Information specified when placing a transcription order that
    provides information on what needs to be transcribed and
    sets other transcription options
    """

    # TODO: Indicate inputs must have at least one element
    inputs = List(value_type=Object(IInput),
                  title=u'A list of media to transcribe',
                  required=True)

    # TODO: What is the default value for when this field is not included?
    verbatim = Bool(title=u'Transcribe the provided files verbatim',
                    description=u"""If true, all filler words (i.e. umm, huh) will be included""",
                    required=False)

    # TODO: What is the default value for when this field is not included?
    timestamps = Bool(title=u'Include timestamps',
                      required=False)

class ITranscriptionOrderRequest(IOrderRequest):
    """
    An object providing information for placing a transcription order
    """

    transcription_options = Object(schema=ITranscriptionOptions,
                                   title=u'Transcription options for a transcription order',
                                   description=u"""Provides information on what needs to be transcribed
                                   and allows for any transcription options to be set""",
                                   required=True)

class ICaption(interface.Interface):
    """
    Caption details for a caption order
    including total length of the audio of media attachments for the order
    """

    total_length_seconds = Number(title=u'The total length (in seconds) of the videos included in the caption order',
                                  required=True)

class ICaptionOrderDetails(IOrderDetails):
    """
    The details of a caption order
    """

    caption = Object(schema=ICaption,
                     title=u'Caption details for the caption order',
                     description=u"""Total length (in seconds) of the videos included in the caption order""",
                     required=True)

OUPUT_FILE_FORMAT_DFXP = u'Dfxp'
OUPUT_FILE_FORMAT_SUBRIP = u'SubRip'
OUPUT_FILE_FORMAT_SCENARIST = u'Scc'
OUPUT_FILE_FORMAT_WEB_VTT = u'WebVtt'
OUPUT_FILE_FORMAT_MAC_CAPTION = u'Mcc'
OUPUT_FILE_FORMAT_TIMED_TEXT = u'Ttml'
OUPUT_FILE_FORMAT_TRANSCRIPT = u'Transcript'
OUPUT_FILE_FORMAT_CHEETAH_CAP = u'CheetahCap'
OUPUT_FILE_FORMAT_SPRUCE_SUBTITLE_FILE = u'Stl'
OUPUT_FILE_FORMAT_QUICKTIME_TIMED_TEXT = u'QTtext'
OUPUT_FILE_FORMAT_AVID_DS_SUBTITLE_FILE = u'AvidDs'
OUPUT_FILE_FORMAT_FACEBOOK_READY_SUBRIP = u'FacebookSubRip'

OUPUT_FILE_FORMAT_ITEMS = (OUPUT_FILE_FORMAT_SUBRIP,
                           OUPUT_FILE_FORMAT_SCENARIST,
                           OUPUT_FILE_FORMAT_MAC_CAPTION,
                           OUPUT_FILE_FORMAT_TIMED_TEXT,
                           OUPUT_FILE_FORMAT_QUICKTIME_TIMED_TEXT,
                           OUPUT_FILE_FORMAT_TRANSCRIPT,
                           OUPUT_FILE_FORMAT_WEB_VTT,
                           OUPUT_FILE_FORMAT_DFXP,
                           OUPUT_FILE_FORMAT_CHEETAH_CAP,
                           OUPUT_FILE_FORMAT_SPRUCE_SUBTITLE_FILE,
                           OUPUT_FILE_FORMAT_AVID_DS_SUBTITLE_FILE,
                           OUPUT_FILE_FORMAT_FACEBOOK_READY_SUBRIP)

OUTPUT_FILE_FORMAT_VOCABULARY = SimpleVocabulary(
    [SimpleTerm(_x) for _x in OUPUT_FILE_FORMAT_ITEMS]
)

#: Rev also has translators in many other languages with limited capacity.
#: Please contact Rev at support@rev.com with your unique needs.

SUBTITLE_LANGUAGE_DUTCH = u'nl'
SUBTITLE_LANGUAGE_ARABIC = u'ar'
SUBTITLE_LANGUAGE_FRENCH = u'fr'
SUBTITLE_LANGUAGE_GERMAN = u'de'
SUBTITLE_LANGUAGE_ITALIAN = u'it'
SUBTITLE_LANGUAGE_RUSSIAN = u'ru'
SUBTITLE_LANGUAGE_SPANISH = u'es'
SUBTITLE_LANGUAGE_PORTUGUESE_BRAZIL = u'pt-br'
SUBTITLE_LANGUAGE_CHINESE_SIMPLIFIED = u'zh-si'
SUBTITLE_LANGUAGE_CHINESE_TRADITIONAL = u'zh-tr'

SUBTITLE_LANGUAGE_ITEMS = (SUBTITLE_LANGUAGE_ARABIC,
                           SUBTITLE_LANGUAGE_CHINESE_SIMPLIFIED,
                           SUBTITLE_LANGUAGE_CHINESE_TRADITIONAL,
                           SUBTITLE_LANGUAGE_DUTCH,
                           SUBTITLE_LANGUAGE_FRENCH,
                           SUBTITLE_LANGUAGE_GERMAN,
                           SUBTITLE_LANGUAGE_ITALIAN,
                           SUBTITLE_LANGUAGE_PORTUGUESE_BRAZIL,
                           SUBTITLE_LANGUAGE_RUSSIAN,
                           SUBTITLE_LANGUAGE_SPANISH)

SUBTITLE_LANGUAGE_VOCABULARY = SimpleVocabulary(
    [SimpleTerm(_x) for _x in SUBTITLE_LANGUAGE_ITEMS]
)

class ICaptionOptions(interface.Interface):
    """
    Information specified when placing a caption order that
    provides information on what needs to be captioned and
    specifies the desired captions output format
    """

    # TODO: Indicate inputs must have at least one element
    inputs = List(value_type=Object(IInput),
                  title=u'A list of media to caption',
                  required=True)

    subtitle_languages = List(value_type=Choice(vocabulary=SUBTITLE_LANGUAGE_VOCABULARY),
                              title=u'A list of language codes to request foreign language subtitles',
                              required=False)

    output_file_formats = List(value_type=Choice(vocabulary=OUTPUT_FILE_FORMAT_VOCABULARY),
                               title=u'A list of file formats the captions should be optimized for',
                               description=u'By default, we optimize for SubRip',
                               required=False)

class ICaptionOrderRequest(IOrderRequest):
    """
    An object providing information for placing a caption order
    """

    non_standard_tat_guarantee = Bool(title=u'Specify that normal turnaround time is not needed',
                                      description=u"""By default, normal turnaround time (false) is assumed.
                                      Note that this value is used as a guideline only.""",
                                      required=False)

    caption_options = Object(schema=ICaptionOptions,
                             title=u'Caption options for a caption order',
                             description=u"""Provides information on what needs to be captioned
                             and specifies the desired captions output format""",
                             required=True)

class ICaptionOrder(ICaptionOrderRequest, ICaptionOrderDetails, IOrder):
    """
    A caption order
    """

class ITranscription(interface.Interface):
    """
    Transcription details for a transcription order
    including total length of the audio of media attachments for the order
    and additional services
    """

    total_length_seconds = Number(title=u'Total length of the audio (in seconds) of media attachments for an order',
                                  required=True)

    verbatim = Bool(title=u'The transcription is verbatim',
                    description=u"""If true, all filler words (i.e. umm, huh) are included in the transcription""",
                    required=True)

    timestamps = Bool(title=u'Timestamps are included in the transcription',
                      required=True)

class ITranscriptionOrderDetails(IOrderDetails):
    """
    The details of a transcription order
    """

    transcription = Object(schema=ITranscription,
                           title=u'Transcription details for the transcription order',
                           description=u"""Total length of the audio (in seconds) of media attachments for the order
                           and additional services""",
                           required=True)

class ITranscriptionOrder(ITranscriptionOrderRequest, ITranscriptionOrderDetails, IOrder):
    """
    A transcription order
    """


from tqdm import tqdm
import requests
import urllib.request as ur
from bs4 import BeautifulSoup

print("Enter the page link:")
page_link = input()
page = ur.urlopen(page_link)
soup = BeautifulSoup(page, 'html.parser')

print('These files will be downloaded:')
for link in soup.find_all('a'):
    tarlink = link.get('href')
    if tarlink.endswith('.tar'):
        print(tarlink)

for link in soup.find_all('a'):
    tar_link = link.get('href')
    if tar_link.endswith('.tar'):
        url = page_link + '/' + tar_link
        print('\n' + tar_link + ' is being downloaded...')
        don = requests.get(url, stream=True)
        with open(tar_link, 'wb') as file_name:
            for part in tqdm(don.iter_content()):
                if part:
                    file_name.write(part)


# -*- coding: utf-8 -*-
"""
Created on Mon May  6 06:58:45 2019
Initial build of genre prediction model.
Parses

@author: night
"""
import pandas as pd
import dill
import numpy as np
#from wordcloud import WordCloud, STOPWORDS

from sklearn.pipeline import Pipeline
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.model_selection import GridSearchCV
from sklearn import base

from sklearn.naive_bayes import MultinomialNB
from sklearn.naive_bayes import ComplementNB
from sklearn.svm import SVC

from sklearn.neighbors import NearestNeighbors

class RowRemoveTransformer(base.BaseEstimator, base.TransformerMixin):

    def __init__(self, min_count=0):
        self.min_count = min_count  # We will need these in transform()

    def fit(self, X, y=None):
        # This transformer doesn't need to learn anything about the data,
        # so it can just return self without any further processing
        return self

    def transform(self, X):
        # Return an array with the same number of rows as X and one
        # column for each in self.col_names
        return [row for row in X if np.sum(row) > self.min_count]

def save_pkl(df, filename):
    with open('data/'+filename+'.pkl','wb') as fobj:
        dill.dump(df,fobj)

def load_pkl(filename):
    with open('data/'+filename+'.pkl','rb') as fobj:
        df = dill.load(fobj)
    return df

def generate_model(data):

    data = data.sample(frac=1).reset_index(drop=True)

    rock_sample = data[data['genre']=='rock'].sample(3300)
    country_sample = data[data['genre']=='country'].sample(3300)
    hiphop_sample = data[data['genre']=='hiphop'].sample(3300)

    sampled_data = pd.concat([rock_sample, hiphop_sample, country_sample])
    sampled_data = data
    X = list(sampled_data.lyrics)
    y = list(sampled_data.genre)
    stop_words = frozenset(["verse", "chorus","instrumental"])

    lyric_class = Pipeline([
        ('ctvect', CountVectorizer(min_df=0, max_df=0.95, stop_words=stop_words, ngram_range=(1,2))), #Vectorizer
        ('tfidf_trans', TfidfTransformer()), #Normalization
#        ('cnb', ComplementNB(alpha=0.1))
        ('mnb', MultinomialNB())
#        ('svc', SVC(probability=True))
    ])

#    parameters = {'mnb__alpha': [0.01, 0.03, 0.05, 0.08], 'ctvect__min_df': [0.1, 0.5, 0.02], 'ctvect__max_df': [0.99]}
    parameters = {'ctvect__min_df': [0, 0.01], 'ctvect__max_df': [0.8, 0.96, 0.99], 'mnb__alpha': [0.01, 0.1, 1]}
    gscv = GridSearchCV(lyric_class, parameters, cv=4, scoring='balanced_accuracy')
    gscv.fit(X, y)
    print(gscv.best_params_)
    print(gscv.best_score_)

    lyric_clf = gscv.best_estimator_

    save_pkl(lyric_clf, 'mnb_notparedData_balancedaccuracy')

    return lyric_clf

def classify_text(model, text):

    print(text)
    print(model.predict_proba(text))
    best_genre = model.predict(text)
    print(best_genre)
    return best_genre

def create_playlist(genre, data, input_text, vocab, num_tracks):
    genre_data = data.loc[data['genre']==genre[0]] #Select genre tracks
    tfidf_matrix = vectorize_it(genre_data, input_text, vocab)
    indices = get_closest_indices(tfidf_matrix,num_tracks)
    track_list = fetch_track_ids(genre_data,indices)
    return track_list

def vectorize_it(genre_data, input_text, vocab):
    input_df = pd.DataFrame(data=[['', input_text, '', '']], columns=['genre', 'lyrics', 'orig_index', 'track_id'])
    genre_data = genre_data.append(input_df, ignore_index=True)

    vector_trans = Pipeline([
        ('ctvect', CountVectorizer(vocabulary=vocab)),
#        ('rrt', RowRemoveTransformer()),
        ('tfidf_trans', TfidfTransformer())
    ])

#    text_vect = ctvect.fit_transform(genre_data.lyrics)

    return vector_trans.fit_transform(genre_data.lyrics)

def get_closest_indices(tfidf_matrix,num_tracks):
    nbrs = NearestNeighbors(n_neighbors=105).fit(tfidf_matrix)
    distances, indices = nbrs.kneighbors(tfidf_matrix[-1,:])
    indices=indices[distances>1] #Remove too-close matches (only 1 word in lyrics)
    indices = indices.flatten()[:num_tracks]
    return indices

def fetch_track_ids(genre_data,indices):
    similar_tracks = pd.Series(indices).map(genre_data.reset_index()['track_id'])
    return similar_tracks

def remove_empties(df):
    return df[df['lyrics'] != ' ']

data = load_pkl('labeled_df')
labels = pd.unique(data.genre)
data = remove_empties(data)

#try:
#    genre_clf = load_pkl('cnb_classifier5')
#except FileNotFoundError:
genre_clf = generate_model(data)

input_text = 'Bring up the old country football'

num_tracks=10

total_vocab = genre_clf.named_steps['ctvect'].vocabulary_

best_genre = classify_text(genre_clf, [input_text])

track_list = create_playlist(best_genre, data, input_text, total_vocab, num_tracks)


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

import os
from typing import Optional

import pytest
import torch

from combustion.vision import (
    append_bbox_label,
    batch_box_target,
    combine_bbox_scores_class,
    combine_box_target,
    filter_bbox_classes,
    flatten_box_target,
    split_bbox_scores_class,
    split_box_target,
    unbatch_box_target,
    visualize_bbox,
)

@pytest.fixture(
    params=[
        (1, 227, 227),
        (3, 227, 227),
        (227, 227),
        (3, 1, 227, 227),
        (1, 1, 227, 227),
    ]
)
def img_shape(request):
    return request.param

@pytest.fixture(params=["Tensor", "np.array"])
def input_type(request):
    return request.param

@pytest.fixture
def img(input_type, img_shape):
    torch.random.manual_seed(42)
    img_t = input_type
    tensor = torch.rand(*img_shape)
    if img_t == "Tensor":
        return tensor
    elif img_t == "np.array":
        return tensor.numpy()
    else:
        raise pytest.UsageError(f"unknown type for fixture image: {img_t}")

@pytest.fixture(params=["classes", "no_classes"])
def label(request, input_type, img_shape):
    if request.param == "no_classes":
        return None
    label_t = input_type
    tensor = torch.Tensor([[1], [2]])
    if len(img_shape) == 4:
        tensor = tensor.unsqueeze_(0).repeat(img_shape[0], 1, 1)
    if label_t == "Tensor":
        return tensor
    elif label_t == "np.array":
        return tensor.numpy()
    else:
        raise pytest.UsageError(f"unknown type for fixture label: {label_t}")

@pytest.fixture
def bbox(input_type, img_shape):
    bbox_t = input_type
    tensor = torch.Tensor([[20, 20, 100, 100], [60, 60, 100, 100]])
    if len(img_shape) == 4:
        tensor = tensor.unsqueeze_(0).repeat(img_shape[0], 1, 1)
    if bbox_t == "Tensor":
        return tensor
    elif bbox_t == "np.array":
        return tensor.numpy()
    else:
        raise pytest.UsageError(f"unknown type for fixture bbox: {bbox_t}")

@pytest.fixture
def class_names():
    return {x: str(x) for x in range(5)}

@pytest.fixture(params=["scores", "no_scores"])
def scores(request, input_type, img_shape):
    if request.param == "no_scores":
        return None
    torch.random.manual_seed(42)
    scores_t = input_type
    if len(img_shape) == 4:
        tensor = torch.rand(img_shape[0], 2, 1)
    else:
        tensor = torch.rand(2, 1)
    if scores_t == "Tensor":
        return tensor
    elif scores_t == "np.array":
        return tensor.numpy()
    else:
        raise pytest.UsageError(f"unknown type for fixture input_type: {input_type}")

class TestVisualizeBbox:

    # Set this to a directory to write out some sample images from test cases
    # DEST: Optional[str] = None
    DEST: Optional[str] = "/home/tidal"

    def save(self, path, result):
        import matplotlib.pyplot as plt

        if os.path.isdir(path):
            plt.imsave(path, result.permute(1, 2, 0).cpu().numpy())

    def test_inputs_unchanged(self, img, label, bbox, class_names, scores):
        def copy(x):
            return torch.as_tensor(x).clone()

        img_c = copy(img)
        bbox_c = copy(bbox)
        label_c = copy(label) if label is not None else None
        scores_c = copy(scores) if scores is not None else None

        result = visualize_bbox(img, bbox=bbox, classes=label, scores=scores, class_names=class_names)

        assert torch.allclose(torch.as_tensor(img), img_c)
        assert torch.allclose(torch.as_tensor(bbox), bbox_c)
        if label is not None:
            assert label_c is not None
            assert torch.allclose(torch.as_tensor(label), label_c)
        if scores is not None:
            assert scores_c is not None
            assert torch.allclose(torch.as_tensor(scores), scores_c)

    def test_visualize_bbox(self, img, label, bbox, class_names, scores):
        if not isinstance(img, torch.Tensor):
            pytest.skip()

        result = visualize_bbox(img, bbox, label, scores, class_names)
        assert isinstance(result, torch.Tensor)
        assert result.shape[-2:] == img.shape[-2:]
        assert result.shape[-3] == 3
        if img.ndim != 2:
            assert result.ndim == img.ndim

        if self.DEST is not None and img.ndim == 3:
            dest = os.path.join(self.DEST, "test_visualize_bbox.png")
            self.save(dest, result)

    def test_class_names(self, img, label, bbox):
        if label is None:
            pytest.skip()
        class_names = {1: "foo", 2: "bar"}
        no_names = visualize_bbox(img, bbox, label)
        names = visualize_bbox(img, bbox, label, class_names=class_names)
        assert names.shape == no_names.shape and not torch.allclose(torch.as_tensor(names), torch.as_tensor(no_names))

        if self.DEST is not None and img.ndim == 3:
            dest = os.path.join(self.DEST, "test_class_names.png")
            self.save(dest, names)

    def test_multiple_scores(self, img, label, bbox, scores):
        torch.random.manual_seed(42)
        if scores is None:
            pytest.skip()
        tensor1 = torch.rand_like(torch.as_tensor(scores))
        tensor2 = torch.rand_like(torch.as_tensor(scores))
        tensor = torch.cat([tensor1, tensor2], dim=-1)

        scores1 = visualize_bbox(img, bbox, label, scores=tensor1)
        scores2 = visualize_bbox(img, bbox, label, scores=tensor)
        assert scores1.shape == scores2.shape and not torch.allclose(torch.as_tensor(scores1), torch.as_tensor(scores2))

        if self.DEST is not None and img.ndim == 3:
            dest = os.path.join(self.DEST, "test_multiple_scores.png")
            self.save(dest, scores2)

    @pytest.mark.usefixtures("cuda_or_skip")
    def test_cuda(self, img, label, bbox, class_names, scores):
        if not isinstance(img, torch.Tensor):
            pytest.skip()

        img = img.cuda()
        bbox = bbox.cuda()
        label = label.cuda() if label is not None else None
        scores = scores.cuda() if scores is not None else None
        result = visualize_bbox(img, bbox, label, scores, class_names)
        assert isinstance(result, torch.Tensor)
        if not img.is_floating_point():
            assert result.dtype == torch.uint8
        else:
            assert result.is_floating_point()
            assert result.max() <= 1
            assert result.min() >= 0
        assert result.shape[-2:] == img.shape[-2:]
        assert result.shape[-3] == 3
        if img.ndim != 2:
            assert result.ndim == img.ndim

        if self.DEST is not None and img.ndim == 3:
            dest = os.path.join(self.DEST, "test_visualize_bbox.png")
            self.save(dest, result)

class TestBboxHelpers:
    @pytest.mark.parametrize("split_label", [False, True, [1, 1]])
    def test_split_box_target_result(self, split_label):
        torch.random.manual_seed(42)
        bbox_target = torch.randint(0, 10, (3, 4, 4))
        label_target = torch.randint(0, 10, (3, 4, 2))
        target = torch.cat([bbox_target, label_target], dim=-1)

        result = split_box_target(target, split_label=split_label)
        bbox = result[0]
        label = result[1:]
        assert torch.allclose(bbox, bbox_target)

        if not split_label:
            assert torch.allclose(torch.cat(label, dim=-1), label_target)
        else:
            for i, sub_label in enumerate(label):
                assert torch.allclose(sub_label, label_target[..., i : i + 1])

    def test_split_box_target_returns_views(self):
        torch.random.manual_seed(42)
        bbox_target = torch.randint(0, 10, (3, 4, 4))
        label_target = torch.randint(0, 10, (3, 4, 2))
        target = torch.cat([bbox_target, label_target], dim=-1)

        bbox, label = split_box_target(target)

        target.mul_(10)
        assert torch.allclose(bbox, target[..., :4])
        assert torch.allclose(label, target[..., 4:])

    @pytest.mark.parametrize("extra_labels", [False, True])
    def test_combine_box_target(self, extra_labels):
        torch.random.manual_seed(42)
        bbox_target = torch.randint(0, 10, (3, 4, 4))
        label_target = torch.randint(0, 10, (3, 4, 2))
        if extra_labels:
            extra_labels = (torch.randint(0, 10, (3, 4, 2)),)
        else:
            extra_labels = ()

        true_target = torch.cat([bbox_target, label_target, *extra_labels], dim=-1)

        target = combine_box_target(bbox_target, label_target, *extra_labels)

        assert torch.allclose(target, true_target)

    @pytest.mark.parametrize("pad_value", [-1, -2])
    def test_batch_box_target(self, pad_value):
        torch.random.manual_seed(42)
        target1 = torch.randint(0, 10, (3, 6))
        target2 = torch.randint(0, 10, (2, 6))

        batch = batch_box_target([target1, target2], pad_value=pad_value)

        assert batch.shape[0] == 2
        assert torch.allclose(batch[0], target1)
        assert torch.allclose(batch[1, :2, :], target2)
        assert (batch[1, 2, :] == pad_value).all()

    def test_batch_box_target_batched_inputs(self):
        torch.random.manual_seed(42)
        target1 = torch.randint(0, 10, (3, 3, 6))
        target2 = torch.randint(0, 10, (2, 2, 6))

        batch = batch_box_target([target1, target2])
        assert batch.shape[-1] == 6
        assert batch.shape[-2] == 3
        assert batch.shape[0] == 5  # 3 + 2
        assert (batch[-1, -1, :] == -1).all()

    @pytest.mark.parametrize("pad_value", [-1, -2])
    def test_unbatch_box_target(self, pad_value):
        torch.random.manual_seed(42)
        target = torch.randint(0, 10, (2, 3, 6))
        target[0, 2, :].fill_(pad_value)

        split_batch = unbatch_box_target(target, pad_value=pad_value)

        assert torch.allclose(target[0, :2, ...], split_batch[0])
        assert torch.allclose(target[1], split_batch[1])

    @pytest.mark.parametrize("pad_value", [-1, -2])
    def test_flatten_box_target(self, pad_value):
        torch.random.manual_seed(42)
        target = torch.randint(0, 10, (2, 3, 6))
        target[0, 2, :].fill_(pad_value)

        flat_batch = flatten_box_target(target, pad_value=pad_value)

        assert flat_batch.ndim == 2
        assert flat_batch.shape[0] == 2 + 3

        expected = torch.cat([target[0, :2, ...], target[1, ...]], dim=0)
        assert torch.allclose(flat_batch, expected)

    @pytest.mark.parametrize("label_size", [1, 2])
    def test_append_bbox_label(self, label_size):
        torch.random.manual_seed(42)
        old_label = torch.randint(0, 10, (2, 4, 6))
        new_label = torch.randint(0, 10, (2, 4, label_size))

        final_label = append_bbox_label(old_label, new_label)
        assert torch.allclose(final_label, torch.cat([old_label, new_label], dim=-1))

    @pytest.mark.parametrize("split_scores", [False, True, [1, 1]])
    def test_split_bbox_scores_class_result(self, split_scores):
        torch.random.manual_seed(42)
        bbox_target = torch.randint(0, 10, (3, 4, 4)).float()
        scores_target = torch.rand(3, 4, 2)
        cls_target = torch.randint(0, 10, (3, 4, 1)).float()
        target = torch.cat([bbox_target, scores_target, cls_target], dim=-1)

        result = split_bbox_scores_class(target, split_scores=split_scores)
        bbox = result[0]
        scores = result[1:-1]
        cls = result[-1]

        assert torch.allclose(bbox, bbox_target)
        assert torch.allclose(cls, cls_target)

        if not split_scores:
            assert torch.allclose(torch.cat(scores, dim=-1), scores_target)
        else:
            for i, sub_scores in enumerate(scores):
                assert torch.allclose(sub_scores, scores_target[..., i : i + 1])

    def test_split_bbox_scores_class_returns_views(self):
        torch.random.manual_seed(42)
        bbox_target = torch.randint(0, 10, (3, 4, 4)).float()
        scores_target = torch.rand(3, 4, 2)
        torch.randint(0, 10, (3, 4, 1)).float()
        target = torch.cat([bbox_target, scores_target], dim=-1)

        result = split_bbox_scores_class(target)
        bbox = result[0]
        scores = result[1]
        cls = result[-1]

        target.mul_(10)
        assert torch.allclose(bbox, target[..., :4])
        assert torch.allclose(scores, target[..., 4:-1])
        assert torch.allclose(cls, target[..., -1:])

    @pytest.mark.parametrize("extra_scores", [False, True])
    def test_combine_bbox_scores_cls(self, extra_scores):
        torch.random.manual_seed(42)
        bbox = torch.randint(0, 10, (3, 4, 4)).float()
        scores = torch.rand(3, 4, 2)
        cls = torch.randint(0, 10, (3, 4, 1))
        if extra_scores:
            extra_scores = (torch.rand(3, 4, 2).float(),)
        else:
            extra_scores = ()

        true_target = torch.cat([bbox, scores, *extra_scores, cls], dim=-1)

        target = combine_bbox_scores_class(bbox, cls, scores, *extra_scores)

        assert torch.allclose(target, true_target)

    @pytest.mark.parametrize("return_inverse", [False, True])
    @pytest.mark.parametrize("keep_classes", [[0], [0, 1], [0, 2]])
    def test_filter_bbox_classes(self, return_inverse, keep_classes):
        torch.random.manual_seed(42)

        possible_classes = set([0, 1, 2])
        if return_inverse:
            set(keep_classes)
        else:
            possible_classes - set(keep_classes)

        classes1 = torch.tensor([0, 1, 2, 1, 0, 0, -1, -1, -1]).unsqueeze_(-1)
        classes2 = torch.tensor([1, 0, 0, 1, 0, -1, -1, -1, -1]).unsqueeze_(-1)

        target = torch.stack([classes1, classes2], dim=0)
        bbox = torch.randint(0, 10, (2, target.shape[-2], 4))
        target = torch.cat([bbox, target], dim=-1).float()

        result = filter_bbox_classes(target, keep_classes=keep_classes, return_inverse=return_inverse)

        for cls in possible_classes:
            if return_inverse and cls in keep_classes:
                assert not (result[..., -1] == cls).any()
            if not return_inverse and cls not in keep_classes:
                assert not (result[..., -1] == cls).any()


import numpy as np
from scipy.optimize import root_scalar
import math
import matplotlib.pyplot as plt

def f(x):
    return ((x**3) - (2*(x**2)) + ((4*x)/3) - (8/27))

# graficar parqa recocnocer el intervalo
x = np.linspace(start=-10, stop=10, num=100)
plt.plot(x, f(x))
plt.grid()
plt.axhline(y=0, linewidth=2, c='k')
plt.axvline(x=0, linewidth=2, c='k')
#plt.show()

solucion = root_scalar(f, method='brentq', bracket=[0, 2], rtol=(2**-80))
print(f"Metodo de Brent:\n\
     - raiz= {solucion.root}\n\
     - Iteraciones ={solucion.iterations}\n")


from tkinter import NE
import imports
from imports import *
import settings
from settings import*
import funzioni
from funzioni import *

#=========================================================================
# CARICO I DATI
print('carico il dataframe')
df = pd.read_excel('data/Informatica.xlsx')
print('dataframe caricato: ')
display(df[0:3])

print('\n=============================\n')

#=========================================================================
# CONSIDERO SOLO LE COLONNE CHE MI INTERESSANO
print('elimino le colonne che non mi interessano')
df = df[colonneUtilizzate]
display(df[0:3])

print('\n=============================\n')

#=========================================================================
# ELIMINO GLI ESAMI CHE NON SONO DEL PRIMO ANNO
print('elimino gli esami che non sono del primo anno')
righeIniziali = df.shape[0]
print('righe iniziali: ',righeIniziali)
if(len(ESAMI_TOTALI) != 0): df = df[df['DES'].isin(ESAMI_TOTALI)]
#report
print('righe eliminate: ',righeIniziali-df.shape[0])
print('righe rimanenti: ',df.shape[0])
print('\n=============================\n')
#=========================================================================
# IN RARI CASI HO PESO NON VALIDO, SISTEMO
modificati = 0
for i in df.index:
    des = df.loc[i,'DES']
    if des == 'FISICA' or des == 'ALGEBRA E GEOMETRIA' or des == 'ALGORITMI E STRUTTURE DATI I' or des == 'ANALISI MATEMATICA':
        if df.loc[i,'PESO'] != 9: modificati+=1
        df.loc[i,'PESO'] = 9
    elif des == 'INGLESE B1':
        if df.loc[i,'PESO'] != 3: modificati+=1
        df.loc[i,'PESO'] = 3
    elif des == 'FONDAMENTI DI PROGRAMMAZIONE A - FONDAMENTI DI PROGRAMMAZIONE B':
        if df.loc[i,'PESO'] != 15: modificati+=1
        df.loc[i,'PESO'] = 15
    elif des == 'ARCHITETTURA DEGLI ELABORATORI':
        if df.loc[i,'PESO'] != 6: modificati+=1
        df.loc[i,'PESO'] = 6

print('PESI sistemati: ',modificati)

#=========================================================================
# segno gli esami contrassegnati con 'P' con 'F'

print('segno gli esami contrassegnati con \'P\' con \'F\'')
cont = 0
for i in df.index:
    a = df.loc[i,'STA_SCE_COD']
    if(a!='S'and a!='F'):
        cont +=1
        df.loc[i,'STA_SCE_COD'] = 'F'
print('ho sistemato ',cont,' esami')
print('\n=============================\n')

#=========================================================================
# ORDINO GLI ESAMI IN ORDINE ALFABETICO

print('ordino gli esami in ordine alfabetico')
df = df.sort_values(by='DES')
display(df)
print('\n=============================\n')
#=========================================================================
# ELIMINO GLI ORARI DA DATA_SUP, DATA_FREQ, DATA_PRIMO_APPELLO, DATA_MAX_APPELLO
print('elimino gli orari dalle date\n')

print('prima:\n')
print(df.iloc[0])
# SEMPLIFICO DATA_FREQ
vDataFreq = df['DATA_FREQ']     #vecchio
nDataFreq = []                  #nuovo

for elem in vDataFreq:
    if pd.isna(elem):
        nDataFreq.append(elem)
    else:
        nDataFreq.append(elem[0:10])

df['DATA_FREQ'] =   nDataFreq

#   SEMPLIFICO DATA_SUP
dateComplete = df['DATA_SUP']
dateAnni = []
for elem in dateComplete:
    if pd.isna(elem):
        dateAnni.append(elem)
    else:
        dateAnni.append(elem[0:10])

df['DATA_SUP'] = dateAnni

#   SEMPLIFICO DATA_PRIMO_APPELLO

vDataPrimoApp = df['DATA_PRIMO_APPELLO']
nDataPrimoApp = []

for elem in vDataPrimoApp:
    if pd.isna(elem):
        nDataPrimoApp.append(elem)
    else:
        nDataPrimoApp.append(elem[0:10])

df['DATA_PRIMO_APPELLO'] = nDataPrimoApp

# SEMPLIFICO DATA_MAX_APPELLO
vData = df['DATA_MAX_APPELLO']     #vecchio
nData = []                  #nuovo

for elem in vData:
    if pd.isna(elem):
        nData.append(elem)
    else:
        nData.append(elem[0:10])

df['DATA_MAX_APPELLO'] = nData

#SEMPLIFICO DATA_CHIUSURA
vDataChius = df['DATA_CHIUSURA']     #vecchio
nDataChius = []                      #nuovo

for elem in vDataChius:
    if pd.isna(elem):
        nDataChius.append(elem)
    else:
        nDataChius.append(elem[0:10])

df['DATA_CHIUSURA'] =   nDataChius

#report
print('\ndopo :\n')
print(df.iloc[0])
print('\n=============================\n')

#=========================================================================
# AGGIUNGO LA COLONNA "PRIMO_ANNO" AL DATAFRAME, CHE INIDICA IL PRIMO ANNO EFFETTIVO DI OGNI STUDENTE

# Cerco il minimo degli anni in cui lo studente ha seguito le lezioni di un corso (aMinimo).
# Probabilmente questo `e il primo anno dello studente.
# A questo punto imposto il primo anno dello studente come:

# 􏰀 aMinimo se l’ anno di avvio della carriera dello studente +1 corrisponde ad aMinimo.
# Questo caso `e quello piu` comune, in cui lo studente si iscrive in un certo anno
# (per esempio a luglio, al termine delle superiori) e poi inizia a dare gli esami l’ anno successivo (verso gennaio/febbraio).
# (il 92.8 % degli esami rientrano in questo caso)
# 􏰀 aMinimo se l’ anno di avvio della carriera dello studente corrisponde a primoAnnoCorsoSeguito. Faccio cosi perch`e,
#  dalle osservazioni che ho fatto, questo caso si verifica principalmente quando lo studente si `e iscritto dopo gennaio.
# (l’ 1.2 % degli esami rientrano in questo caso)
# 􏰀 in tutti gli altri casi lo imposto come anno avvio carriera +1. Questa cosa potrebbe generare inconsistenze,
# ma mi sembra il modo migliore con cui gestirla (il 5.9 % degli esami rientrano in questo caso)

print('aggiungo la colonna \'primo anno\' al dataframe')

primoAnno = []
# caso1 = 0
# caso2 = 0
# caso3 = 0

for i in df.index:

    matricola = df.loc[i,'STU_ID']
    avvCar = df.loc[i,'ANNO_AVVIO_CARRIERA']
    primoACorsoSeg = getAnnoInizioFrequentazioneLezioni(df,matricola)
    annoSup = df.loc[i,'DATA_SUP']

    if pd.notna(annoSup):
        annoSup = str(annoSup)[0:4]
        annoSup = int(annoSup)

    #caso normale (lo studente si iscrive in un certo anno e frequenta lezioni di quell' anno)
    if avvCar+1 == primoACorsoSeg:
        primoAnno.append(primoACorsoSeg)
        # caso2+=1

    #caso in cui lo studente si è iscritto dopo gennaio
    elif avvCar == primoACorsoSeg :
        primoAnno.append(primoACorsoSeg)
        # caso1+=1
        # print(df.loc[i],'\n')

    #se non riesco a stimare con precisione l' anno di inizio, lo imposto come anno avvio carriera +1
    #   questa cosa potrebbe generare dell' errore ma non saprei come altro fare dato che a volte i dati sono incoerenti
    else:
        primoAnno.append(avvCar+1)
        # caso3+=1

df['PRIMO_ANNO'] = primoAnno
# print('caso1: ',caso1)
# print('caso2: ',caso2)
# print('caso3: ',caso3)

print('\n=============================\n')
#=========================================================================

#sistemo questo studente per cui ho visto che il primo anno e' sbagliato
for i in df.index:
    if df.loc[i,'STU_ID']==267757: df.loc[i,'PRIMO_ANNO']=2016
#=========================================================================
#numero di esami e di studenti per anno

#numero di esami per ogni anno
anni = []
for i in df.index: anni.append(df.loc[i,'PRIMO_ANNO'])
anni = uniq(anni)

print('numero di esami negli anni:')
for anno in anni:
    print('numero di esami nell\' anno ',anno,': ',len(df[df['PRIMO_ANNO']==anno]))

#numero di studenti per ogni anno
somme = np.zeros((len(anni)))
matr = calcolaMatricole(df)

for i in range(len(anni)):
    for j in range(len(matr)):
        if matr[j].iloc[0,14] == anni[i]: somme[i] +=1

print('numero di studenti negli anni:')
for i in range(len(anni)):
    print('numero di studenti nell\' anno ',anni[i],': ',somme[i])
#=========================================================================
# gestisco i casi in cui manca DATA_FREQ
#  In 139 casi(5.1% del totale) manca la data di fine lezioni

#   sistemo andando a cercare il data freq di uno studente che ha dato la stessa materia nello stesso anno

print('correggo i data_freq mancanti')

fine_lezioni = df['DATA_FREQ']
correzioniFatte = 0
printed = False

#-----------report iniziale
da_correggere = []
for i in df.index:
    if(pd.isna(df.loc[i,'DATA_FREQ'])):

        anno = df.loc[i,'PRIMO_ANNO']
        esame = df.loc[i,'DES']
        dataFreqCorretta = -1

        for j in df.index:
            primoAnnoAltro = df.loc[j,'PRIMO_ANNO']
            annoDataFreq = df.loc[j,'DATA_FREQ']

            if type(annoDataFreq)==str:
                annoDataFreq = annoDataFreq[0:4]
            if primoAnnoAltro == anno and df.loc[j,'DES'] == esame and annoDataFreq==anno:
                dataFreqCorretta= df.loc[j,'DATA_FREQ']
                break

        #se non risesco a trovare un valore tra i dati degli altri studenti, imposto il primo anno dello studente seguito da un mese e giorno
        #in base a se l' esame e' nel primo o secondo semestre
        if(dataFreqCorretta == -1):
            dataFreqCorretta = df.loc[i,'PRIMO_ANNO']
            dataFreqCorretta = str(dataFreqCorretta)
            if (esame in( ESAMI_PRIMO_SEMESTRE)):
                dataFreqCorretta = dataFreqCorretta + '-01-15'
            else:
                print(dataFreqCorretta)
                dataFreqCorretta = dataFreqCorretta + '-06-10'

        if not printed:
            display(df.loc[i])

        df.loc[i,'DATA_FREQ']=dataFreqCorretta
        correzioniFatte +=1

        if not printed:
            printed = True
            display(df.loc[i])

print('correzioni fatte: ',correzioniFatte)

print('\n=============================\n')

#=========================================================================
# questa colonna non mi serve più
print('elimino la colonna ANNO AVVIO CARRIERA')
df.drop('ANNO_AVVIO_CARRIERA',axis=1,inplace=True)
print('\n=============================\n')
#=========================================================================
# CALCOLO LA FEATURE GIORNI_ESAME_PASSATO (GIORNI DOPO I QUALI LO STUDENTE HA PASSATO L' ESAME)
#   GIORNI_ESAME_NON_SUPERATO               ->  esame non superato
#   numero giorni                           ->  esame superato dopo questi giorni

print('calcolo la feature \'GIORNI ESAME PASSATO\'')

#   conteggio di quanti giorni sono passati prima che lo studente desse l' esame
giorniSup = []
#   date ultima lezione per esame
date_ultime_lez = df['DATA_FREQ']
#   date superamento
date_sup = df['DATA_SUP']
risultati = df['STA_SCE_COD']

for i in df.index:
    #se ho passato l' esame calcolo dopo quanti giorni
    if risultati[i]=='S':

        #per ogni riga ottengo le date che mi interessano
        strUltimaLez = date_ultime_lez[i]
        strSup = date_sup[i]

        #   sostituisco - con / nelle stringhe
        strUltimaLez = strUltimaLez.replace('-','/')
        strSup = strSup.replace('-','/')
        #   calcolo degli oggetti data a partire dalle stringhe
        dataUltimaLez = datetime.strptime(strUltimaLez,'%Y/%m/%d')
        dataSup = datetime.strptime(strSup,'%Y/%m/%d')
        dataSup = dataSup.date()
        dataUltimaLez = dataUltimaLez.date()

        delta = dataSup - dataUltimaLez
        #estraggo i giorni
        delta = delta.days

        #   calcolo dopo quanti giorni dalla fine delle lezioni lo studente ha dato l' esame, e lo aggiungo all' array della nuova feature
        giorniSup.append(delta)

    #se non ho passato l' esame segno -1
    else:
        giorniSup.append(GIORNI_ESAME_NON_SUPERATO)

del(strSup)
del(strUltimaLez)

df['GIORNI_ESAME_PASSATO']=giorniSup

#=========================================================================
# CALCOLO LA FEATURE GIORNI_ESAME_PROVATO (GIORNI DOPO I QUALI LO STUDENTE HA PROVATO L' ESAME PER LA PRIMA VOLTA)

#   GIORNI_ESAME_MAI_PROVATO              ->  prima prova mai fatta   (modificare?)
#   -2              ->  inconsistenza dati
#   numero giorni   ->  esame provato dopo questi giorni

print('calcolo la feature \'GIORNI ESAME PROVATO\'')

#   conteggio di quanti giorni sono passati prima che lo studente desse l' esame
giorniProv = []
#   date ultima lezione per esame
date_ultime_lez = df['DATA_FREQ']
#   date superamento
date_prima_prov = df['DATA_PRIMO_APPELLO']
risultati = df['STA_SCE_COD']

for i in df.index:
    #   per ogni riga ottengo le date che mi interessano
    strUltimaLez = date_ultime_lez[i]
    strPrimaProv = date_prima_prov[i]

    #   caso prima prova mai fatta (data prima prova = nan)
    if(pd.isna(strPrimaProv)):
        giorniProv.append(GIORNI_ESAME_MAI_PROVATO)

    #   altrimenti calcolo il numero di giorni dopo cui è stata fatta la prima prova
    else:
        #   sostituisco - con / nelle stringhe
        strUltimaLez = strUltimaLez.replace('-','/')
        strPrimaProv = strPrimaProv.replace('-','/')
        #   calcolo degli oggetti data a partire dalle stringhe
        dataUltimaLez = datetime.strptime(strUltimaLez,'%Y/%m/%d')
        dataPrimaProv = datetime.strptime(strPrimaProv,'%Y/%m/%d')
        dataUltimaLez = dataUltimaLez.date()
        dataPrimaProv = dataPrimaProv.date()

        delta = dataPrimaProv - dataUltimaLez
        delta = delta.days

        # se mi risulta un delta negativo, i dati sono inconsitenti e quindi segno -2, piu avanti aggiusto con valore medio
        # CAMBIRARE APPROCCIO? VOLENDO POTREI ANCHE METTERE -1
        if delta < 0:
            delta = -2

        #   calcolo dopo quanti giorni dalla fine delle lezioni lo studente ha dato l' esame, e lo aggiungo all' array della nuova feature
        giorniProv.append(delta)

df['GIORNI_ESAME_PROVATO']=giorniProv

display(df)

print('\n=============================\n')

#=========================================================================
# gestione valori mancanti o inconsistenti
#=========================================================================
print('\n=================================')
print('       gestione valori mancanti o inconsistenti     ')
print('=================================\n')

#========================================================================= stampo la situazione prima dell' eliminazione dei valori mancanti
print('\numero righe iniziali: ',len(df))

matricoleTemp = calcolaMatricole(df)

primiAnni = []
for i in range(len(matricoleTemp)):
    primoAnno = matricoleTemp[i].iloc[0,13]
    primiAnni.append(primoAnno)
primiAnni = uniq(primiAnni)

conteggi = np.zeros(len(primiAnni))
for i in range(len(matricoleTemp)):
    primoAnno = matricoleTemp[i].iloc[0,13]
    for j in range(len(primiAnni)):
        if primoAnno == primiAnni[j]:
            conteggi[j]+=1

print('primi anni: ', primiAnni)
print('conteggi: ', conteggi)
print('totale studenti: ',len(matricoleTemp),'\n')
del(matricoleTemp)

#=========================================================================
#non ci sono esami superati per cui manca il numero di giorni esame superato
df[(df['GIORNI_ESAME_PASSATO']==GIORNI_ESAME_NON_SUPERATO) & (df['STA_SCE_COD']=='S')]
#=========================================================================
# sistemo giorni esame passato < 0 impostando data fine lezioni = data superamento (MIGLIORABILE)

print('casi con giorni esame passato < 0, dovuto a data freq > data sup: ',len(df[df['GIORNI_ESAME_PASSATO']<0]))

for i in df.index:
    if df.loc[i,'GIORNI_ESAME_PASSATO']<0:
        df.loc[i,'GIORNI_ESAME_PASSATO']=10
        df.loc[i,'DATA_FREQ']=df.loc[i,'DATA_SUP']

print('sistemo...')
print('casi al termine: ',len(df[df['GIORNI_ESAME_PASSATO']<0]))
#=========================================================================
# ci sono esami superati per cui manca il numero di giorni del primo tentativo, sistemo stimando i valori mancanti
print('casi con giorni esame provato mancante: ',len(df[(df['GIORNI_ESAME_PROVATO']==GIORNI_ESAME_MAI_PROVATO) & (df['STA_SCE_COD']=='S')]))

for i in df.index:
    if df.loc[i,'GIORNI_ESAME_PROVATO']==GIORNI_ESAME_MAI_PROVATO and df.loc[i,'STA_SCE_COD']=='S':
        df.loc[i,'DATA_PRIMO_APPELLO']=df.loc[i,'DATA_FREQ']
        df.loc[i,'GIORNI_ESAME_PROVATO']=0
        numero = 1
        giorniPassato = df.loc[i,'GIORNI_ESAME_PASSATO']
        if giorniPassato > 15 and giorniPassato<40: numero = 2
        elif giorniPassato >=40 and giorniPassato < 60: numero = 3
        else: numero = 4
        df.loc[i,'NUMERO']= numero

print('al termine: ',len(df[(df['GIORNI_ESAME_PROVATO']==GIORNI_ESAME_MAI_PROVATO) & (df['STA_SCE_COD']=='S')]))
#=========================================================================
# ci sono casi con data fine lezioni > data primo tentativo
print('casi con giorni esame provato mancante: ',len(df[df['GIORNI_ESAME_PROVATO']<0]))

for i in df.index:
    if df.loc[i,'GIORNI_ESAME_PROVATO']<0:
        df.loc[i,'DATA_FREQ']=df.loc[i,'DATA_PRIMO_APPELLO']
        df.loc[i,'GIORNI_ESAME_PROVATO'] = 0
print('al termine: ',len(df[df['GIORNI_ESAME_PROVATO']<0]))
#=========================================================================

#=========================================================================
# per 5 studenti mancano i dati di certi esami
#   questi studenti non hanno piu' dato alcun esame anche negli anni successivi, quindi probabilmente gli esami mancanti non sono stati superati
#   quindi aggiungo gli esami mancanti segnandoli come non superati

print('aggiungo gli esami che sono mancanti per certi studenti')

matricole = calcolaMatricole(df)

#----------------------------------------------------------
#   ELIMINO STUDENTI PER CUI MANCANO I DATI DI CERTI ESAMI

# A 2 studenti (0.01% dei casi) mancano le righe relative ad alcuni esami.

DA_SISTEMARE = []

numeroColonne = len(matricole[1].columns)
numeroRighe = len(ESAMI_TOTALI)
numeroCampiPrevisi = numeroColonne*numeroRighe

for i in range (len(matricole)):
    l = len(matricole[i].to_numpy().flatten())
    if l!=numeroCampiPrevisi:
        matricola = matricole[i]
        DA_SISTEMARE.append(matricola.iloc[0,0])

DA_SISTEMARE = uniq(DA_SISTEMARE)

nesamiSistemati = 0
for elem in DA_SISTEMARE:
    nesamiSistemati+= len(df[df['STU_ID'] == elem])

valoriMancanti = len(DA_SISTEMARE)

#===============================================================aggiungo esami mancanti
nEsamiAggiunti = 0
esameNonSuperato = df.iloc[0].copy(deep=True)
esameNonSuperato.loc['STU_ID'] = 0
esameNonSuperato.loc['STA_SCE_COD']='F'
esameNonSuperato.loc['VOTO']=np.nan
esameNonSuperato.loc['LODE_FLG']=0
esameNonSuperato.loc['NUMERO']=0
esameNonSuperato.loc['DATA_SUP']=np.nan
esameNonSuperato.loc['DATA_FREQ']=np.nan
esameNonSuperato.loc['DATA_MAX_APPELLO']=np.nan
esameNonSuperato.loc['DATA_PRIMO_APPELLO']=np.nan
esameNonSuperato.loc['GIORNI_ESAME_PASSATO']=GIORNI_ESAME_NON_SUPERATO
esameNonSuperato.loc['GIORNI_ESAME_PROVATO']=GIORNI_ESAME_MAI_PROVATO

for i in range(len(DA_SISTEMARE)):
    datiStudente = df[df['STU_ID']==DA_SISTEMARE[i]]
    print('studente con esami mancanti:')
    display(datiStudente)

    esamiDati = datiStudente['DES'].tolist()
    for esame in ESAMI_TOTALI:
        if esame not in (esamiDati):

            if esame == 'ALGEBRA E GEOMETRIA' or esame == 'ALGORITMI E STRUTTURE DATI I' or esame == 'ANALISI MATEMATICA' or esame == 'FISICA': peso = 9
            elif esame == 'ARCHITETTURA DEGLI ELABORATORI': peso = 6
            elif esame == 'FONDAMENTI DI PROGRAMMAZIONE A - FONDAMENTI DI PROGRAMMAZIONE B': peso = 15
            else: peso = 3

            nEsamiAggiunti+=1
            nuovoEsame = esameNonSuperato.copy(deep=True)
            nuovoEsame.loc['DES']= esame
            nuovoEsame.loc['PRIMO_ANNO']=datiStudente.iloc[0,13]
            nuovoEsame.loc['PESO']=peso
            nuovoEsame.loc['AA_OFF_ID']=datiStudente.iloc[0,7]
            nuovoEsame.loc['STU_ID']=DA_SISTEMARE[i]
            df= df.append(nuovoEsame,ignore_index = True)
    print('studente con esami mancanti sistemato:')
    # ORDINO GLI ESAMI IN ORDINE ALFABETICO
    df = df.sort_values(by='DES')
    display(df[df['STU_ID']==DA_SISTEMARE[i]])

#===============================================================

print('studenti per cui ci sono esami mancanti: ',valoriMancanti)
print('in totale ho aggiunto: ',nEsamiAggiunti,' esami')
del(matricole)

print('\n=============================\n')

#=========================================================================

print('controlli:')

#CONTROLLI SU POSSIBILI INCONSISTENZE
if len (df[df['GIORNI_ESAME_PASSATO']<0]) > 0:
    print('PROBLEMA: ci sono giorni esame passato < 0')

if len (df[df['GIORNI_ESAME_PASSATO']<0]) > 0:
    print('PROBLEMA: ci sono giorni esame passato < 0')

problema = False
for i in df.index:
    if df.loc[i,'STA_SCE_COD']=='S' and pd.isna(df.loc[i,'VOTO']) and df.loc[i,'DES']!= 'INGLESE B1':
        problema = True
if problema: print('PROBLEMA: ci sono esami superati in cui manca il voto')

print('\n=============================\n')

#=========================================================================

print('rimuovo STA_SCE_COD segnando voto = 0 quando l\' esame non viene superato')
#RIMUVO STA_SCE_COD
#segno voto = 0 nel caso l' esame non sia stato superato
for i in df.index:
    if df.loc[i,'STA_SCE_COD']=='F':
        df.loc[i,'VOTO'] = 0
    #segno 30 come voto di inglese nel caso sia stato superato
    if df.loc[i,'DES']=='INGLESE B1':
        if df.loc[i,'STA_SCE_COD']=='S':
            df.loc[i,'VOTO']= 30

df = df.astype({"VOTO": int})
df.drop('STA_SCE_COD',axis=1,inplace=True)

#=========================================================================
print('rimuovo colonna lode segnando voto = 31 quando uno studente la ottiene')
# #   ELIMINO COLONNA LODE SEGNANDO VOTO 31 AL POSTO DEL FLAG
for i in df.index:
    if df.loc[i,'LODE_FLG'] == 1 and df.loc[i,'VOTO']==30:
        df.loc[i,'VOTO']=31
df.drop('LODE_FLG',axis=1,inplace=True)

display(df)

print('\n=============================\n')
''#=========================================================================
# #sistemo questo studente per cui ho visto che il primo anno e' sbagliato
# for i in df.index:
#     if df.loc[i,'STU_ID']==267757: df.loc[i,'PRIMO_ANNO']=2016

#sistemo qeusti studenti
studentiDaSistemare = [243460,239249,239815,267757]
if MESE_RIFERIMENTO < 4:
    for i in df.index:
        stuId = df.loc[i,'STU_ID']
        if stuId in studentiDaSistemare and df.loc[i,'VOTO']>0:
            if df.loc[i,'DES']=='FONDAMENTI DI PROGRAMMAZIONE A - FONDAMENTI DI PROGRAMMAZIONE B':
                df.loc[i,'VOTO'] = 0
                df.loc[i,'GIORNI_ESAME_PASSATO']=GIORNI_ESAME_NON_SUPERATO
                df.loc[i,'NUMERO'] = 0
                df.loc[i,'GIORNI_ESAME_PROVATO']=GIORNI_ESAME_MAI_PROVATO

#=========================================================================report situazione finale
print('numero righe finali: ',len(df))

matricoleTemp = calcolaMatricole(df)

primiAnni = []
for i in range(len(matricoleTemp)):
    primoAnno = matricoleTemp[i].iloc[0,11]
    primiAnni.append(primoAnno)
primiAnni = uniq(primiAnni)

conteggi = np.zeros(len(primiAnni))
for i in range(len(matricoleTemp)):
    primoAnno = matricoleTemp[i].iloc[0,11]
    for j in range(len(primiAnni)):
        if primoAnno == primiAnni[j]:
            conteggi[j]+=1

print('primi anni: ', primiAnni)
print('conteggi: ', conteggi)
print('totale studenti: ',len(matricoleTemp))
del(matricoleTemp)


import argparse
import time
import pickle
import profile
import torch
import torch.optim as optim

from utils import TextData, similar_words, save_vectors
from model import SkipGramModel

def train(model, optimizer, train_data, epoch):
    n_batch = len(train_data)
    model.train()
    start_time = time.time()
    for idx, (u_pos, v_pos, u_neg, v_neg) in enumerate(train_data):
        model.zero_grad()

        loss = model(u_pos, v_pos, u_neg, v_neg)
        # loss = model(batch[0], batch[1], batch[2])
        loss.backward()
        optimizer.step()

        if idx % 50 == 0 and idx > 0:
            elapsed = time.time() - start_time
            print('| epoch {:3d} | {:5d}/{:5d} batches | {:5.2f} ms/batch | loss {:5.2f} '
                .format(epoch, idx, n_batch, elapsed * 20, loss.item()))
            start_time = time.time()

def evaluate(model, eval_data):
    pass

def save(model):
    torch.save(model.state_dict(), 'params.pkl')
    print('saved parameters ...')
    # model.load_state_dict(torch.load('params.pkl'))

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='test')
    parser.add_argument('--path', type=str, default='./.data/wikitext-2/')
    parser.add_argument('--n_hidden', type=int, default=100)
    parser.add_argument('--batch_size', type=int, default=2048)
    parser.add_argument('--gram', type=int, default=2)
    parser.add_argument('--tie', type=bool, default=False)
    parser.add_argument('--epochs', type=int, default=300)
    parser.add_argument('--subsample', type=bool, default=True)
    parser.add_argument('--n_negative', type=int, default=3)
    args = parser.parse_args()

    data = TextData(args.path)
    # # profile.run('.data.batchfiy(n_neg=args.n_negative, gram=args.gram, bsz=args.batch_size, subsample=args.subsample)')
    # train_data = data.batchfiy(n_neg=args.n_negative, gram=args.gram, bsz=args.batch_size, subsample=args.subsample)
    #
    # # with open('batches.pkl', 'wb') as f: ??????
    # # with open('.data.pkl', 'rb') as f:
    # #     .data = pickle.load(f)
    #
    # # eval_data = .data.evaluate
    #
    # model = SkipGramModel(data.n_tokens, args.n_hidden)
    # # model.load_state_dict(torch.load('params.pkl'))
    #
    # optimizer = optim.SparseAdam(model.parameters())
    #
    # for epoch in range(args.epochs):
    #     train(model, optimizer, train_data, epoch)
    #     # evaluate(model, eval_data)
    # save(model)

    params = torch.load('results/params.pkl')
    similar_words(data.dictionary, params['u_embeddings.weight'], ['China', 'one'])
    save_vectors(data.dictionary, params['u_embeddings.weight'])


#!/usr/bin/python3
"""
This Handles all the api Restful actions for Customers
"""
from flask import jsonify, request, make_response
from api.v1.views import app_views
from models.customer import Customer
from models import storage
from flask_jwt_extended import jwt_required, get_jwt_identity, create_access_token
from datetime import timedelta
from api.v1.errors import error_response, bad_request, not_found

@app_views.route('/customer_login', methods=['POST'], strict_slashes=False)
def customer_login():
    """ This returns a token for an authenticated customer """

    form_request = request.form

    if not form_request:
        return bad_request("Not a JSON")
    if 'phone_no' not in form_request:
        return bad_request("Missing Phone Number")

    for customer in storage.all(Customer).values():
        if customer.phone_no == form_request['phone_no']:
            expires = timedelta(seconds=3600)
            access_token = create_access_token(identity=customer.phone_no, expires_delta=expires)
            return make_response(jsonify({'access_token': access_token, 'id': customer.id}), 200)

    return bad_request("Invalid credentials")

@app_views.route('/customers', methods=['GET'], strict_slashes=False)
@jwt_required()
def get_customers():

    """This retrieves a list all customers"""
    customers_list = [cust.to_dict() for cust in storage.all(Customer).values()]
    return jsonify(customers_list)

@app_views.route('/customers/<customer_id>', methods=['GET'], strict_slashes=False)
def get_customer(customer_id):
    """This retrieves a customer based on its id"""

    customer = storage.get(Customer, customer_id)
    if not customer:
        return not_found("customer not found")
    return jsonify(customer.to_dict())

@app_views.route('/customers', methods=['POST'], strict_slashes=False)
def post_customer():
    """This creates a new customer object"""

    form_request = request.form

    if not form_request:
        return bad_request("Not form-data")

    required = ['name', 'phone_no', 'address', 'email']
    for val in required:
        if val not in form_request:
            return bad_request(f"Missing {val}")

    for cust in storage.all(Customer).values():
        if form_request['email'] == cust.email:
            return bad_request("Email Already Exist")
        if form_request['phone_no'] == cust.phone_no:
            return bad_request("Phone Already Exist")

    customer = Customer(**form_request)
    customer.save()
    return make_response(jsonify(customer.to_dict()), 201)

@app_views.route('/customers/<customer_id>', methods=['PUT'], strict_slashes=False)
def put_customer(customer_id):
    """Updates a particular customer's attributes"""

    customer = storage.get(Customer, customer_id)
    if not customer:
        return not_found()
    form_request = request.form
    if not form_request:
        return bad_request("Not form-data")
    ignore_list = ['id', 'updated_at', 'created_at']

    for key, value in form_request.items():
        if key not in ignore_list:
            setattr(customer, key, value)

    storage.save()
    return make_response(jsonify(customer.to_dict()), 200)

@app_views.route('/customers/<customer_id>', methods=['DELETE'], strict_slashes=False)
def delete_customer(customer_id):
    """Deletes a paticular customer object """

    customer = storage.get(Customer, customer_id)
    if not customer:
        return not_found()

    storage.delete(customer)
    storage.save()

    return make_response(jsonify({}), 200)


import json
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework.authentication import TokenAuthentication, BasicAuthentication
from mineriaApp.Models.MongoModels import Fuente
from mineriaApp.Serializers.MongoSerializers import FuenteSerializer
from mineriaApp.Services.FuenteService import FuenteService

class FuenteView(APIView):
    authentication_classes = [BasicAuthentication, TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def get(self, request):
        """Devuelve las fuentes"""
        data = request.data

        if 'ids' in data.keys():
            ids = data['ids']
            fuente_list = FuenteService.get_by_ids(ids)
            serializer = FuenteSerializer(fuente_list, many=True)
        else:
            raise AttributeError("Falta el parámetro Ids o está vacio")

        return Response(serializer.data)

    def post(self, request):
        """Inserta las entradas"""
        data = request.data

        fuentes = []
        for r in data:
            if "type" not in r.keys():
                fuentes.append(Fuente(nombre=r["nombre"]))

        fuentes_saved = FuenteService.save_objects(fuentes)

        fuentes_ids = [str(ent.id) for ent in fuentes_saved]

        content = {"ids": fuentes_ids}
        return Response(content)


def pagination(list_of_obj, per_page_limit):
    list_length = len(list_of_obj)
    if list_length == per_page_limit:
        has_continue = True
    else:
        has_continue = False
    if list_length:
        start_id = list_of_obj[-1]['_id']
    else:
        start_id = None
    return start_id, has_continue


import numpy as np
from flask import Flask, request, jsonify, render_template

import pickle

app = Flask(__name__)
model_RF=pickle.load(open('PlacementAnalysis_RF.pkl', 'rb'))
model_KNN=pickle.load(open('PlacementAnalysis_KNN.pkl', 'rb'))
model_DT=pickle.load(open('PlacementAnalysis_DT.pkl', 'rb'))
model_SVM_L=pickle.load(open('PlacementAnalysis_SVM_linear.pkl', 'rb'))
model_SVM_R=pickle.load(open('PlacementAnalysis_SVM_RBF.pkl', 'rb'))
model_SVM_S=pickle.load(open('PlacementAnalysis_SVM_Sigmoid.pkl', 'rb'))
model_NB=pickle.load(open('PlacementAnalysis_NB.pkl', 'rb'))

@app.route('/')
def home():

    return render_template("index.html")

@app.route('/predict',methods=['GET'])
def predict():

    ten = float(request.args.get('ten'))
    twell = float(request.args.get('twell'))
    btech = float(request.args.get('btech'))
    seven = float(request.args.get('seven'))
    six = float(request.args.get('six'))
    five = float(request.args.get('five'))
    final = float(request.args.get('final'))
    med = float(request.args.get('med'))

    prediction = model_RF.predict([[ten, twell, btech, seven, six, five, final, med]])

    if prediction == [1]:
      return render_template('index.html', prediction_text='Congratulations you will be placed')
    else:
      return render_template('index.html', prediction_text='Sorry you will not be placed, better luck next time')

if __name__ == "__main__":
    app.run(debug=True)


import json
from django.shortcuts import render
from django.views.generic import TemplateView
import django.dispatch
from django.db import IntegrityError
from django.http import JsonResponse

from .websterapi import GetWordDefinition
from users.models import Word, Profile

class HomePageView(TemplateView):
    template_name = 'home.html'

    def request_to_history(self, user, word):
        check = Profile.objects.filter(user_id = user.id, history_id = word.id).exists()
        if not check:
            profile = Profile.objects.create(user_id = user.id, history_id = word.id)
            profile.save()

    def request_to_local_history(self, user, word):
        self.request_to_history(user, word)
        check = Profile.objects.filter(user_id = user.id, local_history_id = word.id).exists()
        if not check:
            profile = Profile.objects.create(user_id = user.id, local_history_id = word.id)
            profile.save()
            return True

    def handle_ajax_request(self, request):
        profile = Profile.objects.filter(user_id = request.user.id).exclude(local_history = None)
        word_list = []
        for entry in profile:
            word_list.append(str(entry.local_history))
        list_data_json = (list(word_list))

        data = {
            'words': list(word_list),
            }
        return JsonResponse(data, safe = False)

    def profile_check(self, request, word):
        word_check = Word.objects.get(word = word.lower())
        check = Profile.objects.filter(user_id = request.user.id, local_history_id = word_check.id).exists()
        return True if check else False

    def get(self, request, *args, **kwargs):
        if request.is_ajax():
            if 'to_local_history' in request.GET:
                word = request.GET.get('to_local_history')
                word_to_local_history = Word.objects.get(word = word.lower())
                if self.request_to_local_history(request.user, word_to_local_history):
                    data = {'word': word.lower()}
                    return JsonResponse(data, safe = False)
            elif 'delete' in request.GET:
                delete_request = request.GET.get('delete')
                delete_word = Word.objects.get(word = delete_request.lower())
                Profile.objects.get(user_id = request.user.id, history_id = delete_word.id).delete()
            else:
                return self.handle_ajax_request(request)
        if 'to_local_history' in request.GET:
            word = request.GET.get('to_local_history')
        else:
            word = request.GET.get('word')
        if word != None and word != '':
            result = GetWordDefinition(word).get_definition()
            if 'Error_links' in result:
                return(render(request, self.template_name, {'Error_links': result['Error_links'], 'search': word.capitalize()}))
            else:

                ### Saving new word to database

                try:
                    word_to_db = Word.objects.create(word = word.lower())
                    word_to_db.save()
                except IntegrityError as e:
                    print(f'Word "{word}" already exisits in db')

                ### Saving word to search history

                if request.user.add_all:
                    word_to_history = Word.objects.get(word = word.lower())
                    self.request_to_history(request.user, word_to_history)

                ### Check if already added

                added = self.profile_check(request, word)

                definition = result[0]
                if len(result) > 1:
                    general_info = result[1]
                else:
                    general_info = None
                return(render(request, self.template_name, {'definition': definition, 'general_info': general_info, 'search': word.capitalize(), 'added': added}))
        else:
            return(render(request, self.template_name))


from django.urls import reverse
from django.test import TestCase
from django.test import Client
from tests.factories.gbe_factories import (
    ProfileFactory,
)
from tests.functions.gbe_functions import (
    grant_privilege,
    is_login_page,
    login_as,
)
from tests.contexts.show_context import ShowContext

class TestTemplateList(TestCase):
    view_name = 'list_template'

    def setUp(self):
        self.client = Client()
        self.privileged_profile = ProfileFactory()
        self.url = reverse(self.view_name,
                           urlconf="gbe.email.urls")

    def test_no_login_gives_error(self):
        response = self.client.get(self.url, follow=True)
        redirect_url = "%s?next=%s" % (reverse('login'), self.url)
        self.assertRedirects(response, redirect_url)
        self.assertTrue(is_login_page(response))

    def test_no_priv(self):
        login_as(ProfileFactory(), self)
        response = self.client.get(self.url)
        self.assertEqual(response.status_code, 403)

    def test_volunteer_coordinator(self):
        grant_privilege(self.privileged_profile.user_object,
                        'Volunteer Coordinator')
        login_as(self.privileged_profile, self)
        response = self.client.get(self.url)

        templates = ["volunteer accepted",
                     "volunteer awaiting approval",
                     "volunteer duplicate",
                     "volunteer no decision",
                     "volunteer reject",
                     "volunteer schedule update",
                     "volunteer changed schedule",
                     "volunteer submission notification",
                     "volunteer update notification",
                     "volunteer wait list",
                     "volunteer withdrawn", ]
        for template in templates:
            self.assertContains(response, template)

    def test_act_coordinator(self):
        context = ShowContext()
        grant_privilege(self.privileged_profile.user_object,
                        'Act Coordinator')
        login_as(self.privileged_profile, self)
        response = self.client.get(self.url)

        templates = ["act accepted - %s" % context.sched_event.title.lower(),
                     "act duplicate",
                     "act no decision",
                     "act reject",
                     "act submission notification",
                     "act wait list - %s" % context.sched_event.title.lower(),
                     "act withdrawn", ]
        for template in templates:
            self.assertContains(response, template)

    def test_basic_bid_coordinators(self):
        for bid_type in ['Class', 'Costume', 'Vendor']:
            grant_privilege(self.privileged_profile.user_object,
                            '%s Coordinator' % bid_type)
            login_as(self.privileged_profile, self)
            response = self.client.get(self.url)

            templates = ["%s accepted",
                         "%s duplicate",
                         "%s no decision",
                         "%s reject",
                         "%s submission notification",
                         "%s wait list",
                         "%s withdrawn", ]
            for template in templates:
                self.assertContains(response, template % bid_type.lower())

    def test_scheduler(self):
        grant_privilege(self.privileged_profile.user_object,
                        'Scheduling Mavens')
        login_as(self.privileged_profile, self)
        response = self.client.get(self.url)
        self.assertContains(response, "daily schedule")

    def test_registrar(self):
        grant_privilege(self.privileged_profile.user_object, 'Registrar')
        login_as(self.privileged_profile, self)
        response = self.client.get(self.url)
        self.assertContains(response, "unsubscribe email")


class_split = {
    "CoraFull": {"train": 40, 'dev': 15, 'test': 15},  # Sufficient number of base classes
    "Reddit": {"train": 21, 'dev': 10, 'test': 10},
    "ogbn-arxiv": {"train": 20, 'dev': 10, 'test': 10},
    "Coauthor-CS": {"train": 5, 'dev': 5, 'test': 5},
    "Amazon-Computer": {"train": 4, 'dev': 3, 'test': 3},
    "Cora": {"train": 3, 'dev': 2, 'test': 2},
    "CiteSeer": {"train": 2, 'dev': 2, 'test': 2},
}

config = {
    "seed": 1234,
    "dataset": "CiteSeer", # CoraFull(70)/CiteSeer(6)/ogbn-arxiv(40)/Cora(7)/Amazon-Computer(10)/Coauthor-CS(15)
    "batch_size": 128,
    "n_way": 2,
    "k_shot": 3,
    "m_qry": 10,
    "test_num": 20,
    "patience": 10,
    "sup": False,
    "epoch_num": 10000,
}


import cv2
import tensorflow as tf
import numpy as np
from tensorflow import keras

facec = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')#replace with better classifer
model = keras.models.load_model('ACCURATEMODEL.hdf5')
font = cv2.FONT_HERSHEY_SIMPLEX

class VideoCamera(object):
    def __init__(self):
        self.video = cv2.VideoCapture(0)

    def __del__(self):
        self.video.release()

    # returns camera frames along with bounding boxes and predictions
    def get_frame(self):
        _, fr = self.video.read()
        faces = facec.detectMultiScale(fr)

        for (x, y, w, h) in faces:
            fc = fr[y:y + h, x:x + w]
            roi = cv2.resize(fc, (224, 224))
            roi = tf.keras.applications.mobilenet.preprocess_input(roi)
            roi = np.expand_dims(roi, 0)
            pred = model.predict(roi)
            p = np.argmax(pred, 1)
            if p == 0:
                state = 'NOT DROWSY'
            if p == 1:
                state = "DROWSY"
            cv2.putText(fr, str(state), (x, y), font, 1, ((0,128,128)), 2)
            cv2.rectangle(fr, (x, y), (x + w, y + h), ((0,255,0)), 2)
        cv2.imshow('Stream', fr)
        cv2.waitKey(1)

vc = VideoCamera()
while True:
    vc.get_frame()