import os, sys, glob
from __main__ import vtk, qt, ctk, slicer
from functools import partial

from Guidelet import GuideletLoadable, GuideletLogic, GuideletTest, GuideletWidget
from Guidelet import Guidelet
import PerkTutorCouchDB
import logging
import time

class EyeTutor(GuideletLoadable):
  """
  Uses GuideletLoadable class, available at:
  This is designed for cataract surgery and other related ophthalmology applications.
  """

  def __init__(self, parent):
    GuideletLoadable.__init__(self, parent)
    self.parent.title = "Eye Tutor"
    self.parent.categories = [ "Training" ]
    self.parent.dependencies = [ "PerkTutorCouchDB" ]
    self.parent.contributors = [ "Matthew S. Holden (Perk Lab; Queen's University)" ]
    self.parent.helpText = """  """
    self.parent.acknowledgementText = """  """

class EyeTutorWidget(GuideletWidget):
  """Uses GuideletWidget base class, available at:
  """

  def __init__(self, parent = None):
    GuideletWidget.__init__(self, parent)

  def setup(self):
    GuideletWidget.setup(self)

  def addLauncherWidgets(self):
    GuideletWidget.addLauncherWidgets(self)

    # Launcher settings for databases
    self.databaseSettingsGroupBox = ctk.ctkCollapsibleGroupBox()
    self.databaseSettingsGroupBox.setTitle( "Database settings" )
    self.databaseSettingsGroupBox.collapsed = True
    self.databaseSettingsLayout = qt.QFormLayout( self.databaseSettingsGroupBox )
    self.launcherFormLayout.addRow( self.databaseSettingsGroupBox )

    self.databaseFullRemoteAddressLineEdit = qt.QLineEdit()
    self.databaseFullRemoteAddressLineEdit.setEchoMode( qt.QLineEdit.Password )
    self.databaseSettingsLayout.addRow( "Full remote database address", self.databaseFullRemoteAddressLineEdit )

    self.fileServerSessionLineEdit = qt.QLineEdit()
    self.databaseSettingsLayout.addRow( "File server session name", self.fileServerSessionLineEdit )

    self.fileServerClientLineEdit = qt.QLineEdit()
    self.databaseSettingsLayout.addRow( "File server client path", self.fileServerClientLineEdit )

    settings = slicer.app.userSettings()
    self.databaseFullRemoteAddressLineEdit.setText( settings.value( self.moduleName + "/Configurations/" + self.selectedConfigurationName + "/DatabaseFullRemoteAddress" ) )
    self.fileServerSessionLineEdit.setText( settings.value( self.moduleName + "/Configurations/" + self.selectedConfigurationName + "/FileServerSession" ) )
    self.fileServerClientLineEdit.setText( settings.value( self.moduleName + "/Configurations/" + self.selectedConfigurationName + "/FileServerClient" ) )

    self.databaseFullRemoteAddressLineEdit.connect( 'editingFinished()', self.onDatabaseFullRemoteAddressEdited )
    self.fileServerSessionLineEdit.connect( 'editingFinished()', self.onFileServerSessionEdited )
    self.fileServerClientLineEdit.connect( 'editingFinished()', self.onFileServerClientEdited )

  def onConfigurationChanged(self, selectedConfigurationName):
    GuideletWidget.onConfigurationChanged(self, selectedConfigurationName)

    settings = slicer.app.userSettings()
    self.databaseFullRemoteAddressLineEdit.setText( settings.value( self.moduleName + "/Configurations/" + self.selectedConfigurationName + "/DatabaseFullRemoteAddress" ) )
    self.fileServerSessionLineEdit.setText( settings.value( self.moduleName + "/Configurations/" + self.selectedConfigurationName + "/FileServerSession" ) )
    self.fileServerClientLineEdit.setText( settings.value( self.moduleName + "/Configurations/" + self.selectedConfigurationName + "/FileServerClient" ) )

  def onDatabaseFullRemoteAddressEdited( self ):
    self.guideletLogic.updateSettings( { "DatabaseFullRemoteAddress": str( self.databaseFullRemoteAddressLineEdit.text ) }, self.selectedConfigurationName )

  def onFileServerSessionEdited( self ):
    self.guideletLogic.updateSettings( { "FileServerSession": str( self.fileServerSessionLineEdit.text ) }, self.selectedConfigurationName )

  def onFileServerClientEdited( self ):
    self.guideletLogic.updateSettings( { "FileServerClient": str( self.fileServerClientLineEdit.text ) }, self.selectedConfigurationName )

  def createGuideletInstance(self):
    return EyeTutorGuidelet(None, self.guideletLogic, self.selectedConfigurationName)

  def createGuideletLogic(self):
    return EyeTutorLogic()

class EyeTutorLogic(GuideletLogic):
  """Uses GuideletLogic base class, available at:
  """ #TODO add path

  def __init__(self, parent = None):
    GuideletLogic.__init__(self, parent)

    self.addValuesToDefaultConfiguration()

  def addValuesToDefaultConfiguration( self ):
    GuideletLogic.addValuesToDefaultConfiguration( self )
    moduleDir = os.path.dirname( slicer.modules.eyetutor.path )

    settingsDict = {}
    settingsDict[ 'StyleSheet' ] = os.path.join( moduleDir, 'Resources', 'StyleSheets', 'EyeTutorStyle.qss' ) #overwrites the default setting param of base
    settingsDict[ 'RecordingFilenamePrefix' ] = 'EyeTutorRec-'
    settingsDict[ 'SavedScenesDirectory' ] = os.path.join( moduleDir, 'SavedScenes' ) #overwrites the default setting param of base
    settingsDict[ 'UltrasoundBrightnessControl' ] = '' #overwrites the default setting param of base
    settingsDict[ 'FileServerLocalDirectory' ] = os.path.join( slicer.app.temporaryPath, "EyeTutor" )
    settingsDict[ 'HasBorderInFullScreen' ] = 'True'

    self.updateSettings( settingsDict, 'Default' )

class EyeTutorTest(GuideletTest):
  """This is the test case for your scripted module.
  """

  def runTest(self):
    """Run as few or as many tests as needed here.
    """
    GuideletTest.runTest(self)
    #self.test_EyeTutor1() #add applet specific tests here

class EyeTutorGuidelet( Guidelet ):

  EYEBALL_RADIUS = 13.0 # millimeters
  TOOL_CALIBRATION_TIME = 5.0 # seconds
  TOOL_SPECIFICATIONS = [
    { "Name": "ForcepAngle", "Color": [ 0, 0, 0 ], "Length": 50 },
    { "Name": "ForcepBlue", "Color": [ 0, 0, 0 ], "Length": 50 },
    { "Name": "ForcepSilver", "Color": [ 0, 0, 0 ], "Length": 50 },
    { "Name": "SyringeFat", "Color": [ 0, 0, 0 ], "Length": 50 },
    { "Name": "SyringeThin", "Color": [ 0, 0, 0 ], "Length": 50 },
    { "Name": "SyringeGreen", "Color": [ 0, 0, 0 ], "Length": 50 },
    { "Name": "SyringeYellow", "Color": [ 0, 0, 0 ], "Length": 50 },
    { "Name": "ScalpelAngle", "Color": [ 0, 0, 0 ], "Length": 50 },
    { "Name": "ScalpelStraight", "Color": [ 0, 0, 0 ], "Length": 50 },
    { "Name": "BluePickOval", "Color": [ 0, 0, 0 ], "Length": 50 },
    { "Name": "BluePickAngle", "Color": [ 0, 0, 0 ], "Length": 50 },
    { "Name": "SilverPickOval", "Color": [ 0, 0, 0 ], "Length": 50 },
    { "Name": "SilverPickAngle", "Color": [ 0, 0, 0 ], "Length": 50 },
    { "Name": "Injector", "Color": [ 0, 0, 0 ], "Length": 50 },
    { "Name": "Ultrasound", "Color": [ 0, 0, 0 ], "Length": 50 }
  ] # Length in millimeters

  def __init__( self, parent, logic, configurationName = 'Default' ):

    Guidelet.__init__( self, parent, logic, configurationName )
    logging.debug( 'EyeTutorGuidelet.__init__' )

    self.modulePath = os.path.dirname( slicer.modules.eyetutor.path )
    self.moduleResourcesPath = os.path.join( self.modulePath, 'Resources' )

    # Set up main frame
    self.sliceletDockWidget.setObjectName( 'EyeTutorPanel' )
    self.sliceletDockWidget.setWindowTitle( 'Eye Tutor' )
    self.mainWindow.setWindowTitle( 'Eye Tutor' )
    self.mainWindow.windowIcon = qt.QIcon( os.path.join( self.moduleResourcesPath, 'Icons', 'EyeTutor.png' ) )

    self.layoutManager.setLayout( slicer.vtkMRMLLayoutNode.SlicerLayoutNone )

    # Setup user ID
    self.userID = None

    self.userLayouts = dict()
    self.userLayouts[ "Guidance" ] = slicer.vtkMRMLLayoutNode.SlicerLayoutOneUp3DView
    self.userLayouts[ "NoGuidance" ] = slicer.vtkMRMLLayoutNode.SlicerLayoutNone

    # Setup logic for database
    self.getDependentModuleLogics()

  def createFeaturePanels( self ):
    # This function sets up the GUI
    featurePanelList = Guidelet.createFeaturePanels( self )
    self.addActionsToUltrasoundPanel()

    # Create and add the login panel
    self.loginCollapsibleButton = ctk.ctkCollapsibleButton()
    self.createLoginPanel()

    # Create and add the calibration panel
    self.calibrationCollapsibleButton = ctk.ctkCollapsibleButton()
    self.createCalibrationPanel()

    # Create and add the assessment panel
    self.assessmentCollapsibleButton = ctk.ctkCollapsibleButton()
    self.createAssessmentPanel()

    # Create and add the logout button
    self.logoutButton = qt.QPushButton( 'Save + Logout' )
    self.createLogoutButton()

    # Modify the panels for the current setup needs
    self.advancedCollapsibleButton.hide()
    self.logoutButton.hide()
    self.ultrasoundCollapsibleButton.hide() # for now
    self.calibrationCollapsibleButton.hide()
    self.assessmentCollapsibleButton.hide()

    return [ self.loginCollapsibleButton, self.ultrasoundCollapsibleButton, self.calibrationCollapsibleButton, self.assessmentCollapsibleButton, self.logoutButton ]

  def __del__( self ):#common
    self.cleanup()

  # Clean up when guidelet is closed
  def cleanup( self ): #common
    Guidelet.cleanup( self )
    logging.debug( 'cleanup' )

  def setupConnections( self ):
    logging.debug( 'EyeTutorGuidelet.setupConnections()' )
    Guidelet.setupConnections( self )

    self.userIDLineEdit.connect( 'returnPressed()', self.login )
    self.loginButton.connect( 'clicked()', self.login )
    self.loginExitButton.connect( 'clicked()', self.onExitButtonClicked )
    self.loginReturnButton.connect( 'clicked()', self.onShowFullSlicerInterfaceClicked )

    self.logoutButton.connect( 'clicked()', self.logout )

    self.ultrasound.startStopRecordingButton.connect( 'clicked(bool)', self.onStartStopRecordingClicked )

    self.assessmentButton.connect( 'clicked()', self.onAssessmentButtonClicked )

    self.pivotCalibrationButton.connect( 'clicked()', partial( self.onToolCalibrationClicked, "Pivot" ) )
    self.spinCalibrationButton.connect( 'clicked()', partial( self.onToolCalibrationClicked, "Spin" ) )
    self.viewAlignmentButton.connect( 'clicked()', self.resetAllViews )
    self.toolCalibrationSamplingTimer.connect( 'timeout()', self.onToolCalibrationSamplingTimeout )

    slicer.mrmlScene.AddObserver( vtk.vtkCommand.ModifiedEvent, self.updateRecordingsTable )

    # Keyboard shortcuts
    if ( not hasattr( self, 'startStopShortcutPlus' ) or self.startStopShortcutPlus is None ):
      self.startStopShortcutPlus = qt.QShortcut( qt.QKeySequence( "+" ), self.sliceletDockWidget )
    self.startStopShortcutPlus.connect( 'activated()', self.ultrasound.startStopRecordingButton.click )

  def setupScene( self ): #applet specific
    logging.debug('setupScene')

    # This will automatically create the ReferenceToRas transform
    Guidelet.setupScene( self )
    self.referenceToRas = self.ultrasound.referenceToRas

    # Tools
    logging.debug( 'Create tools' )

    # Set up the tool transforms and models to be received from PLUS
    self.toolTipToReference = dict()
    self.toolSideToReference = dict()
    self.toolTipToToolSide = dict()
    self.toolModel = dict()
    for toolSpecs in self.TOOL_SPECIFICATIONS:
      toolName = toolSpecs[ "Name" ]
      toolColor = toolSpecs[ "Color" ]
      toolLength = toolSpecs[ "Length" ]

      # Final Transforms
      currToolTipToReferenceName = self.getToolTipToReferenceTransformName( toolName )
      currToolTipToReference = slicer.mrmlScene.GetFirstNodeByName( currToolTipToReferenceName )
      if not currToolTipToReference:
        currToolTipToReference = slicer.vtkMRMLLinearTransformNode() # Identity
        currToolTipToReference.SetName( currToolTipToReferenceName )
        slicer.mrmlScene.AddNode( currToolTipToReference )
      self.toolTipToReference[ toolName ] = currToolTipToReference

      for side in [ "A", "B" ]:
        # Side marker Transforms
        currToolSideToReferenceName = self.getToolSideToReferenceTransformName( toolName, side )
        currToolTipToToolSideName = self.getToolTipToToolSideTransformName( toolName, side )

        currToolSideToReference = slicer.mrmlScene.GetFirstNodeByName( currToolSideToReferenceName )
        if not currToolSideToReference:
          currToolSideToReference = slicer.vtkMRMLLinearTransformNode() # Identity
          currToolSideToReference.SetName( currToolSideToReferenceName )
          slicer.mrmlScene.AddNode( currToolSideToReference )
        self.toolSideToReference[ toolName ] = currToolSideToReference

        currToolTipToToolSide = slicer.mrmlScene.GetFirstNodeByName( currToolTipToToolSideName )
        if not currToolTipToToolSide:
          currToolTipToToolFilePath = os.path.join( self.moduleResourcesPath, currToolTipToToolSideName + '.h5' )
          [ success, currToolTipToToolSide ] = slicer.util.loadTransform( currToolTipToToolFilePath, returnNode = True )
          if not success:
            logging.error( "Could not read the tool tip to tool transform for " + currToolTipToToolSideName + "." )
            currToolTipToToolSide = slicer.vtkMRMLLinearTransformNode() # Identity
            slicer.mrmlScene.AddNode( currToolTipToToolSide )
          currToolTipToToolSide.SetName( currToolTipToToolSideName )
        currToolTipToToolSide.SetAttribute( "ToolTipToToolSide", "True" )
        self.toolTipToToolSide[ toolName ] = currToolTipToToolSide

        # Add the observer so we can update the final transforms as needed
        currToolSideToReference.AddObserver( slicer.vtkMRMLTransformNode.TransformModifiedEvent, partial( self.updateToolToReferenceTransformFromSide, currToolTipToReference, currToolTipToToolSide ) )
        # Put the transforms into the hierarchy
        currToolTipToToolSide.SetAndObserveTransformNodeID( currToolSideToReference.GetID() )
        currToolSideToReference.SetAndObserveTransformNodeID( self.referenceToRas.GetID() )

      # Models
      currToolModelName = self.getToolModelName( toolName )
      currToolModel = slicer.mrmlScene.GetFirstNodeByName( currToolModelName )
      if not currToolModel:
        currToolModel = self.cmLogic.CreateNeedle( toolLength, 1.0, 0.0, False )
        currToolModel.SetName( currToolModelName )
        currToolModel.GetDisplayNode().SetColor( toolColor )
      self.toolModel[ toolName ] = currToolModel

      # Set up the nodes in the transform tree
      currToolModel.SetAndObserveTransformNodeID( currToolTipToReference.GetID() )
      currToolTipToReference.SetAndObserveTransformNodeID( self.referenceToRas.GetID() )

    # Eye model
    logging.debug( 'Create eye model' )

    self.eyeModel = slicer.mrmlScene.GetFirstNodeByName( "EyeModel" )
    if not self.eyeModel:
      currEyeModelPath = os.path.join( self.moduleResourcesPath, "EyeModel.stl" )
      [ success, self.eyeModel ] = slicer.util.loadModel( currEyeModelPath, returnNode = True )
      if not success:
        self.eyeModel = self.cmLogic.CreateSphere( self.EYEBALL_RADIUS ) # Radius of plastic eyeballs
      self.eyeModel.SetName( "EyeModel" )
      self.eyeModel.GetDisplayNode().SetColor( [ 0.5, 0.5, 0.5 ] )

    # Setup metrics
    self.setupMetrics( os.path.join( self.moduleResourcesPath, "Metrics" ) )

    # Setup the views of the scene appropriately
    self.setLayoutForCurrentUser()

    # Hide the image slices from 3D
    self.displayImageSliceIn3D( "Red", False )
    self.displayImageSliceIn3D( "Yellow", False )
    self.displayImageSliceIn3D( "Green", False )

    # Ensure that the sequence browser toolbar(s) is not made visible
    sequenceBrowserToolBars = slicer.util.mainWindow().findChildren( "qMRMLSequenceBrowserToolBar" )
    for toolBar in sequenceBrowserToolBars:
      toolBar.connect( 'visibilityChanged(bool)', partial( self.setSequenceBrowserToolBarsVisible, False ) )

    # Hide slice view annotations (patient name, scale, color bar, etc.) as they
    # decrease reslicing performance by 20%-100%
    logging.debug( 'Hide slice view annotations' )
    import DataProbe
    dataProbeUtil=DataProbe.DataProbeLib.DataProbeUtil()
    dataProbeParameterNode=dataProbeUtil.getParameterNode()
    dataProbeParameterNode.SetParameter( 'showSliceViewAnnotations', '0' )

  def updateToolToReferenceTransformFromSide( self, toolTipToReference, toolTipToToolSide, toolSideToReference, eventID ):
    toolTipToReferenceMatrix = vtk.vtkMatrix4x4()
    slicer.vtkMRMLTransformNode.GetMatrixTransformBetweenNodes( toolTipToToolSide, self.referenceToRas, toolTipToReferenceMatrix )
    toolTipToReference.SetMatrixTransformToParent( toolTipToReferenceMatrix )

  def disconnect( self ):#TODO see connect
    logging.debug( 'EyeTutor.disconnect()' )
    Guidelet.disconnect( self )

    self.userIDLineEdit.connect( 'returnPressed()', self.login )
    self.loginButton.disconnect( 'clicked()', self.login )
    self.loginExitButton.disconnect( 'clicked()', self.onExitButtonClicked )
    self.loginReturnButton.disconnect( 'clicked()', self.onShowFullSlicerInterfaceClicked )

    self.logoutButton.disconnect( 'clicked()', self.logout )

    self.ultrasound.startStopRecordingButton.disconnect( 'clicked(bool)', self.onStartStopRecordingClicked )

    self.assessmentButton.disconnect( 'clicked()', self.onAssessmentButtonClicked )

    self.pivotCalibrationButton.disconnect( 'clicked()', partial( self.onToolCalibrationClicked, "Pivot" ) )
    self.spinCalibrationButton.disconnect( 'clicked()', partial( self.onToolCalibrationClicked, "Spin" ) )
    self.viewAlignmentButton.disconnect( 'clicked()', self.resetAllViews )
    self.toolCalibrationSamplingTimer.disconnect( 'timeout()', self.onToolCalibrationSamplingTimeout )

    slicer.mrmlScene.RemoveObserver( vtk.vtkCommand.ModifiedEvent, self.updateRecordingsTable )

    # Keyboard shortcuts
    self.startStopShortcutPlus.disconnect( 'activated()', self.ultrasound.startStopRecordingButton.click )

  def setupTopPanel(self):
    pass

  def resetAllViews(self):
    # Change the ReferenceToRAS such that the the eyeball center is the eyeball radius extended from the tool tip
    toolTipToTool = self.toolTipToToolSelector.currentNode()
    if toolTipToTool is None:
      logging.debug( "Cannot calibration. No tool tip to tool matrix selected." )
    toolTipToReferenceMatrix = vtk.vtkMatrix4x4()
    toolTipToTool.GetMatrixTransformToNode( self.referenceToRas, toolTipToReferenceMatrix )
    eyeballCener_ToolTip = [ 0, 0, self.EYEBALL_RADIUS, 1 ] # By definition, user holds the tool on the surface of the eyball pointing toward the eyeball center, with the tool end "up"
    eyeballCenter_Reference = [ 0, 0, 0, 1 ]
    toolTipToReferenceMatrix.MultiplyPoint( eyeballCener_ToolTip, eyeballCenter_Reference )

    referenceToRasMatrix = vtk.vtkMatrix4x4()
    referenceToRasMatrix.SetElement( 0, 3, -eyeballCenter_Reference[ 0 ] )
    referenceToRasMatrix.SetElement( 1, 3, -eyeballCenter_Reference[ 1 ] )
    referenceToRasMatrix.SetElement( 2, 3, -eyeballCenter_Reference[ 2 ] )
    self.referenceToRas.SetMatrixTransformToParent( referenceToRasMatrix )

    toolShaft_ToolTip = [ 0, 0, -1, 0 ]
    toolTipToRasMatrix = vtk.vtkMatrix4x4()
    toolTipToTool.GetMatrixTransformToWorld( toolTipToRasMatrix )
    toolShaft_Ras = [ 0, 0, 0, 0 ]
    toolTipToRasMatrix.MultiplyPoint( toolShaft_ToolTip, toolShaft_Ras )

    # Setup the cameras for the 3D views
    cameraNodes = slicer.mrmlScene.GetNodesByClass( "vtkMRMLCameraNode" )
    if ( cameraNodes.GetNumberOfItems() > 0 ):
      camera0 = cameraNodes.GetItemAsObject( 0 )
      camera0.SetFocalPoint( 0, 0, 0 )
      camera0.SetViewUp( toolShaft_Ras[ 0:3 ] )
      camera0.ResetClippingRange()

  def addActionsToUltrasoundPanel( self ):
    self.ultrasoundCollapsibleButton.text = "Recording"

    # Recordings table
    self.recordingsTable = qt.QTableWidget()
    self.recordingsTable.setRowCount( 0 )
    self.recordingsTable.setColumnCount( 1 )
    self.recordingsTable.setHorizontalHeaderLabels( [ "Recording name" ] )
    if ( qt.qVersion()[0] == '5' ): # Used instead of SLICER_HAVE_QT5
      self.recordingsTable.horizontalHeader().setSectionResizeMode( 0, qt.QHeaderView.Stretch )
    else:
      self.recordingsTable.horizontalHeader().setResizeMode( 0, qt.QHeaderView.Stretch )

    # Put them on the GUI
    self.ultrasoundLayout.addRow( self.recordingsTable )

  def createLoginPanel( self ):
    self.loginCollapsibleButton.setProperty( 'collapsedHeight', 20 )
    self.loginCollapsibleButton.text = "Login"
    self.loginCollapsibleButton.collapsed = False
    self.sliceletPanelLayout.addWidget( self.loginCollapsibleButton )

    self.loginLayout = qt.QFormLayout()
    self.loginCollapsibleButton.setLayout( self.loginLayout )

    # Login user ID text field
    self.userIDLineEdit = qt.QLineEdit( "" )

    # Login button
    self.loginButton = qt.QPushButton( 'Login' )
    self.loginButton.setCheckable( False )

    # Exit button
    self.loginExitButton = qt.QPushButton( 'Exit' )
    self.loginExitButton.setCheckable( False )

    # Return button
    self.loginReturnButton = qt.QPushButton( 'Return' )
    self.loginReturnButton.setCheckable( False )

    # Put them on the GUI
    self.loginLayout.addRow( self.userIDLineEdit )
    self.loginLayout.addRow( self.loginButton )
    self.loginLayout.addRow( qt.QLabel() )
    self.loginLayout.addRow( self.loginExitButton )
    self.loginLayout.addRow( self.loginReturnButton ) # For debugging purposes

  def createCalibrationPanel( self ):
    self.calibrationCollapsibleButton.setProperty( 'collapsedHeight', 20 )
    self.calibrationCollapsibleButton.text = "Calibration"
    self.calibrationCollapsibleButton.collapsed = False
    self.sliceletPanelLayout.addWidget( self.calibrationCollapsibleButton )

    self.calibrationLayout = qt.QFormLayout()
    self.calibrationCollapsibleButton.setLayout( self.calibrationLayout )

    # Tool selector
    self.toolTipToToolSelector = slicer.qMRMLNodeComboBox()
    self.toolTipToToolSelector.nodeTypes = [ "vtkMRMLLinearTransformNode" ]
    self.toolTipToToolSelector.addEnabled = False
    self.toolTipToToolSelector.removeEnabled = False
    self.toolTipToToolSelector.addAttribute( "vtkMRMLLinearTransformNode", "ToolTipToToolSide" )
    self.toolTipToToolSelector.setMRMLScene( slicer.mrmlScene )

    # Pivot calibration button
    self.pivotCalibrationButton = qt.QPushButton( 'Pivot Calibration' )
    self.pivotCalibrationButton.setCheckable( False )

    # Spin calibration button
    self.spinCalibrationButton = qt.QPushButton( 'Spin Calibration' )
    self.spinCalibrationButton.setCheckable( False )

    # View alignment button
    self.viewAlignmentButton = qt.QPushButton( 'Reset Views' )
    self.viewAlignmentButton.setCheckable( False )

    # Calibration status label
    self.calibrationStatusLabel = qt.QLabel( "" )

    # Tool calibration sampling timer
    self.toolCalibrationSamplingTimer = qt.QTimer()
    self.toolCalibrationSamplingTimer.setInterval( 500 ) # milliseconds
    self.toolCalibrationSamplingTimer.setSingleShot( False )

    # Put them on the GUI
    self.calibrationLayout.addRow( self.toolTipToToolSelector )
    self.calibrationLayout.addRow( self.pivotCalibrationButton )
    self.calibrationLayout.addRow( self.spinCalibrationButton )
    self.calibrationLayout.addRow( self.viewAlignmentButton )
    self.calibrationLayout.addRow( self.calibrationStatusLabel )

  def createAssessmentPanel( self ):
    self.assessmentCollapsibleButton.setProperty( 'collapsedHeight', 20 )
    self.assessmentCollapsibleButton.text = "Assessment"
    self.assessmentCollapsibleButton.collapsed = False
    self.sliceletPanelLayout.addWidget( self.assessmentCollapsibleButton )

    self.assessmentLayout = qt.QFormLayout()
    self.assessmentCollapsibleButton.setLayout( self.assessmentLayout )

    # Assessment button
    self.assessmentButton = qt.QPushButton( "Assess" )
    self.assessmentButton.setCheckable( False )

    # Metrics table label
    self.metricsTableLabel = qt.QLabel( "Metrics" )

    # Metrics table widget
    self.metricsTableWidget = slicer.qSlicerMetricsTableWidget()
    self.metricsTableWidget.setExpandHeightToContents(False)
    self.metricsTableWidget.setShowMetricRoles(True)
    self.metricsTableWidget.setMRMLScene(slicer.mrmlScene)
    self.metricsTableWidget.setMetricsTableSelectionRowVisible( False )

    # Put them on the GUI
    self.assessmentLayout.addRow( self.assessmentButton )
    self.assessmentLayout.addRow( self.metricsTableLabel )
    self.assessmentLayout.addRow( self.metricsTableWidget )

  def createLogoutButton( self ):
    # Logout
    self.logoutButton.setCheckable( False )

    self.sliceletPanelLayout.addWidget( qt.QLabel() ) # Blank row for spacing between logout and other panels
    self.sliceletPanelLayout.addWidget( self.logoutButton )

  def updateRecordingsTable(self, observer, eventid):
    numberOfNodes = slicer.mrmlScene.GetNumberOfNodesByClass( "vtkMRMLSequenceBrowserNode" )
    self.recordingsTable.setRowCount( numberOfNodes )

    # If a change has been made to the scene with a new sequence browser node,
    # update the table, displaying the name of the node
    for nodeNumber in xrange( numberOfNodes ):
      currSequenceBrowserNode = slicer.mrmlScene.GetNthNodeByClass( nodeNumber, "vtkMRMLSequenceBrowserNode" )
      recordingsTableItem = qt.QTableWidgetItem( currSequenceBrowserNode.GetName() )

      # Add items to the table
      self.recordingsTable.setItem(nodeNumber, 0, recordingsTableItem)

  def login( self ):
    self.userID = self.userIDLineEdit.text
    self.userIDLineEdit.setText( "" )

    # Adjust the layout
    if ( not self.setLayoutForCurrentUser() ):
      return
    self.loginCollapsibleButton.hide()
    self.ultrasoundCollapsibleButton.show()
    self.ultrasoundCollapsibleButton.collapsed = False
    self.calibrationCollapsibleButton.show()
    self.assessmentCollapsibleButton.show()
    self.logoutButton.show()

    # Setup the scene and parameters
    self.parameterNode = self.logic.createParameterNode()
    self.setupConnectorNode()
    self.setupScene()

  def logout( self ):
    # Stop any ongoing recording
    if ( self.ultrasound.startStopRecordingButton.checked ):
      self.ultrasound.startStopRecordingButton.click() # Simulate the user clicking the stop button before logging out

    # Clear the scene and user ID
    slicer.mrmlScene.Clear( 0 )
    self.userID = None

    # Adjust the layout
    self.setLayoutForCurrentUser()
    self.loginCollapsibleButton.show()
    self.loginCollapsibleButton.collapsed = False
    self.ultrasoundCollapsibleButton.hide()
    self.calibrationCollapsibleButton.hide()
    self.assessmentCollapsibleButton.hide()
    self.logoutButton.hide()

  def saveRecording( self, browserNode ):
    # Create the necessary data fields for saving with Perk Tutor CouchDB
    userID = ( "UserID", str( self.userID ) )
    studyID = ( "StudyID", str( "EyeTutor" ) )
    trialID = ( "TrialID", str( "Practice" ) )
    skillLevel = ( "SkillLevel", str( self.layoutManager.layout ) )
    status = ( "Status", str( "Complete" ) )
    date = ( "Date", time.strftime( "%Y/%m/%d-%H:%M:%S" ) )
    metricsComputed = ( "MetricsComputed", False )
    dataFields = dict( [ userID, studyID, trialID, skillLevel, status, date, metricsComputed ] ) #creates dict from list of tuples, format for saving

    localDirectory = self.parameterNode.GetParameter( "FileServerLocalDirectory" )
    serverSessionName = self.parameterNode.GetParameter( "FileServerSession" )
    serverFtpClient = self.parameterNode.GetParameter( "FileServerClient" )
    self.ptcLogic.uploadSession( dataFields, browserNode, localDirectory, serverSessionName, serverFtpClient )

  def getDependentModuleLogics( self ):
    self.cmLogic = slicer.modules.createmodels.logic()
    self.sbLogic = slicer.modules.sequencebrowser.logic()
    self.pcLogic = slicer.modules.pivotcalibration.logic()
    self.peLogic = slicer.modules.perkevaluator.logic()

    self.ptcLogic = PerkTutorCouchDB.PerkTutorCouchDBLogic()
    # Attempt to initialize the database if not already initialized
    fullRemoteAddress = self.parameterNode.GetParameter( "DatabaseFullRemoteAddress" )
    try:
      self.ptcLogic.updateDatabase( PerkTutorCouchDB.PERK_TUTOR_DATABASE_NAME, fullRemoteAddress )
    except Exception as e:
      logging.warning( e )

  def setLayoutForCurrentUser( self ):
    if ( self.userID is None ):
      self.layoutManager.setLayout( slicer.vtkMRMLLayoutNode.SlicerLayoutNone )
      return False

    for currUserGroupName in self.userLayouts:
      currUserGroupFile = open( os.path.join( self.moduleResourcesPath, 'UserGroups', currUserGroupName + ".txt" ) )
      currUserGroupIDs = currUserGroupFile.read().splitlines()
      if ( self.userID in currUserGroupIDs ):
        self.layoutManager.setLayout( self.userLayouts[ currUserGroupName ] )
        return True

    logging.info( "EyeTutorGuidelet::setLayoutForCurrentUser: Could not find user with ID: " + self.userID + "." )
    self.layoutManager.setLayout( slicer.vtkMRMLLayoutNode.SlicerLayoutNone )
    return False

  def setSequenceBrowserToolBarsVisible( self, visible, wasVisible = False ):
    sequenceBrowserToolBars = slicer.util.mainWindow().findChildren( "qMRMLSequenceBrowserToolBar" )
    for toolBar in sequenceBrowserToolBars:
      toolBar.setVisible( visible )

  def startSequenceBrowserRecording( self, browserNode ):
    if ( browserNode is None ):
      return

    browserNode.SetName( slicer.mrmlScene.GetUniqueNameByString( self.userID + "-Recording" ) )
    # Create and populate a sequence browser node if the recording started
    browserNode.SetScene( slicer.mrmlScene )
    slicer.mrmlScene.AddNode( browserNode )

    modifiedFlag = browserNode.StartModify()
    for currToolTipToReference in self.toolTipToReference.values():
      self.sbLogic.AddSynchronizedNode( None, currToolTipToReference, browserNode )

    # Stop overwriting and saving changes to all nodes
    browserNode.SetRecording( None, True )
    browserNode.SetOverwriteProxyName( None, False )
    browserNode.SetSaveChanges( None, False )
    browserNode.EndModify( modifiedFlag )

    browserNode.SetRecordMasterOnly( False )
    browserNode.SetRecordingActive( True )

  def stopSequenceBrowserRecording( self, browserNode ):
    if ( browserNode is None ):
      return

    browserNode.SetRecordingActive( False )
    browserNode.SetRecording( None, False )

    self.saveRecording( browserNode )

  def onStartStopRecordingClicked( self ):
    if self.ultrasound.startStopRecordingButton.isChecked():
      self.eyeTutorSequenceBrowserNode = slicer.vtkMRMLSequenceBrowserNode()
      self.startSequenceBrowserRecording( self.eyeTutorSequenceBrowserNode )
    else:
      self.stopSequenceBrowserRecording( self.eyeTutorSequenceBrowserNode )

  def onToolCalibrationClicked( self, mode ):
    self.calibrationMode = mode # pivot or spin
    self.calibrationToolTipToTool = self.toolTipToToolSelector.currentNode()
    self.calibrationCollapsibleButton.setEnabled( False )

    currToolToReference = None
    self.calibrationToolTipToTool = self.toolTipToToolSelector.currentNode()
    if self.calibrationToolTipToTool:
      currToolToReference = self.calibrationToolTipToTool.GetParentTransformNode()
    if not currToolToReference:
      logging.debug( "Cannot find tool to reference node for " + self.calibrationToolTipToTool + "." )
      return

    self.pcLogic.SetAndObserveTransformNode( currToolToReference )
    self.stopCalibrationTime = time.time() + self.TOOL_CALIBRATION_TIME
    self.pcLogic.SetRecordingState( True )
    self.toolCalibrationSamplingTimer.start()
    self.onToolCalibrationSamplingTimeout()

  def onToolCalibrationSamplingTimeout( self ):
    currTime = time.time()
    self.calibrationStatusLabel.setText( "Tool calibration time remaining: " + str( round( self.stopCalibrationTime - currTime, 1 ) ) + " seconds." )
    if currTime > self.stopCalibrationTime:
      self.computeToolCalibration()

  def computeToolCalibration( self ):
    self.toolCalibrationSamplingTimer.stop()

    currToolTipToToolMatrix = vtk.vtkMatrix4x4()

    success = False
    if ( self.calibrationMode == "Pivot" ):
      self.pcLogic.SetToolTipToToolMatrix( currToolTipToToolMatrix ) # Reset
      success = self.pcLogic.ComputePivotCalibration()
      error = self.pcLogic.GetPivotRMSE()
    else:
      success = self.pcLogic.ComputeSpinCalibration()
      error = self.pcLogic.GetSpinRMSE()

    self.pcLogic.GetToolTipToToolMatrix( currToolTipToToolMatrix )

    if success:
      self.calibrationStatusLabel.setText( "Tool calibration succeeded. Error: " + str( round( error, 2 ) ) + "." )
      self.calibrationToolTipToTool.SetMatrixTransformToParent( currToolTipToToolMatrix )
      slicer.util.saveNode( self.calibrationToolTipToTool, os.path.join( self.moduleResourcesPath, self.calibrationToolTipToTool.GetName() + ".h5" ) )
    else:
      self.calibrationStatusLabel.setText( "Tool calibration failed: " + self.pcLogic.GetErrorText() + "." )

    # Restore the previous state
    self.pcLogic.ClearToolToReferenceMatrices()
    self.calibrationMode = "" # pivot or spin
    self.calibrationToolTipToTool = None
    self.calibrationCollapsibleButton.setEnabled( True )

  def setupMetrics(self, metricsDirectory):
    # Import all of the metric scripts and create the metric instances
    self.perkEvaluatorNode = slicer.vtkMRMLPerkEvaluatorNode()
    self.perkEvaluatorNode.SetScene( slicer.mrmlScene )
    slicer.mrmlScene.AddNode( self.perkEvaluatorNode )

    self.metricsTableNode = slicer.vtkMRMLTableNode()
    self.metricsTableNode.SetScene( slicer.mrmlScene )
    slicer.mrmlScene.AddNode( self.metricsTableNode )

    self.perkEvaluatorNode.SetMetricsTableID( self.metricsTableNode.GetID() )

    # Remove all existing metric scripts and instances from the scene
    metricInstanceNodes = slicer.mrmlScene.GetNodesByClass( "vtkMRMLMetricInstanceNode" )
    for i in range( metricInstanceNodes.GetNumberOfItems() ):
      currentNode = metricInstanceNodes.GetItemAsObject( i )
      slicer.mrmlScene.RemoveNode( currentNode )
    metricScriptNodes = slicer.mrmlScene.GetNodesByClass( "vtkMRMLMetricScriptNode" )
    for i in range( metricScriptNodes.GetNumberOfItems() ):
      currentNode = metricScriptNodes.GetItemAsObject( i )
      slicer.mrmlScene.RemoveNode( currentNode )

    # Add time and path length
    # These metrics are non-shread and non-pervasive versions
    __, activeTimeScript = slicer.util.loadNodeFromFile( os.path.join( metricsDirectory, "ActiveTime.py" ), "Python Metric Script", {}, True )
    __, pathLengthScript = slicer.util.loadNodeFromFile( os.path.join( metricsDirectory, "PathLength.py" ), "Python Metric Script", {}, True )

    for currToolTipToTool in self.toolTipToReference.values():
      currToolActiveTime = self.peLogic.CreateMetricInstance( activeTimeScript )
      currToolActiveTime.SetRoleID( currToolTipToTool.GetID(), "Any", slicer.vtkMRMLMetricInstanceNode.TransformRole )
      self.perkEvaluatorNode.AddMetricInstanceID( currToolActiveTime.GetID() )

      currToolPathLength = self.peLogic.CreateMetricInstance( pathLengthScript )
      currToolPathLength.SetRoleID( currToolTipToTool.GetID(), "Any", slicer.vtkMRMLMetricInstanceNode.TransformRole )
      self.perkEvaluatorNode.AddMetricInstanceID( currToolPathLength.GetID() )

  def onAssessmentButtonClicked(self):
    self.perkEvaluatorNode.SetTrackedSequenceBrowserNodeID( self.eyeTutorSequenceBrowserNode.GetID() )

    analysisProgressDialog = slicer.qSlicerPerkEvaluatorAnalysisDialogWidget()
    analysisProgressDialog.setPerkEvaluatorNode( self.perkEvaluatorNode )
    analysisProgressDialog.show()
    self.peLogic.ComputeMetrics(self.perkEvaluatorNode)
    analysisProgressDialog.hide()

    self.metricsTableWidget.setMetricsTableNode( self.metricsTableNode )

  def displayImageSliceIn3D( self, sliceName, visible ):\
    # Do not display the image slices in 3D
    sliceWidget = slicer.app.layoutManager().sliceWidget( sliceName )
    if ( sliceWidget is None ):
      return
    sliceNode = sliceWidget.sliceView().mrmlSliceNode()
    if ( sliceNode is None ):
      return
    sliceNode.SetSliceVisible( visible )

  def showDefaultView( self ):
    pass # Override to prevent showing red-slice view when returning to recording

  @staticmethod
  def getToolSideToReferenceTransformName( toolName, side = "" ):
    toolToReferenceTransformName = toolName + side + "ToReference"
    toolToReferenceTransformName = toolToReferenceTransformName[ 0:20 ] # Truncate after 20 character due to OpenIgtLink specifications
    return toolToReferenceTransformName

  @staticmethod
  def getToolTipToToolSideTransformName( toolName, side = "" ):
    toolTipToToolTransformName = toolName + side + "TipTo" + toolName + side
    # toolTipToToolTransformName = toolTipToToolTransformName[ 0:20 ] # Truncate after 20 character due to OpenIgtLink specifications # Not needed, not sent by OpenIgtLink
    return toolTipToToolTransformName

  @staticmethod
  def getToolTipToReferenceTransformName( toolName ):
    toolTipToReferenceTransformName = toolName  + "TipToReference"
    # toolTipToReferenceTransformName = toolTipToReferenceTransformName[ 0:20 ]
    return toolTipToReferenceTransformName

  @staticmethod
  def getToolModelName(toolName):
    toolModelName = toolName + "Model"
    # toolModelName = toolModelName[ 0:20 ] # Truncate after 20 character due to OpenIgtLink specifications # Not needed, not sent by OpenIgtLink
    return toolModelName


import random
import telebot

# import webbrowser
# import time

bot_token = '988563200:AAHTscEL3pmsgAnSsQwdVuhpfAqjbmyrMMs'
bot = telebot.TeleBot(token=bot_token)

@bot.message_handler(func=lambda message: message.voice is not None)
def aud(message):
    bot.reply_to(message, 'its an audio')

@bot.message_handler(content_types=['sticker'])
def per(message):
    if message.sticker.emoji == "👋":
        rand = ['1.tgs', '2.webp', '3.tgs', '5.tgs', '6.tgs', '7.tgs']
        sti = open('stickers/hi/' + random.choice(rand), 'rb')
        bot.send_sticker(message.chat.id, sti)
    elif message.sticker.emoji == '😡' or message.sticker.emoji == '😠':
        rand = ['1.tgs', '2.tgs', '3.tgs', '5.tgs', '6.tgs', '7.tgs', '8.webp', '9.webp']
        sti = open('stickers/shock/' + random.choice(rand), 'rb')
        bot.send_sticker(message.chat.id, sti)
    elif message.sticker.emoji == '🤦♂' or message.sticker.emoji == '🙄' or message.sticker.emoji == "😑":
        rand = ['1.tgs', '2.tgs', '3.tgs', '5.tgs', '6.tgs', '7.tgs', '8.webp', '9.webp']
        sti = open('stickers/shock/' + random.choice(rand), 'rb')
        bot.send_sticker(message.chat.id, sti)
    else:
        rand = ['tgs1.tgs', 'tgs2.tgs', 'tgs3.tgs', 'tgs4.tgs', 'tgs5.tgs', 'tgs6.tgs', 'tgs7.tgs', 'tgs8.tgs',
                'tgs9.tgs', 'tgs10.tgs', 'h (1).tgs', 'h (2).tgs', 'h (4).tgs', 'h (3).tgs', 'h (5).tgs', 'h (6).tgs',
                'h (7).tgs', 'h (8).tgs', 'h (9).tgs', 'h (10).tgs', 'h (11).tgs', 'h (12).tgs', 'hw (1).tgs',
                'hw (2).tgs', 'hw (3).tgs', 'hw (4).tgs', 'hw (5).tgs', 'hw (6).tgs', 'hw (7).tgs', 'hw (8).tgs',
                'hw (9).tgs', 'hw (10).tgs', 'hw (11).tgs', 'hw (12).tgs', 'hw (13).tgs', 'hw (14).tgs', 'hw (15).tgs']
        sti = open('stickers/Randstickers/' + random.choice(rand), 'rb')
        bot.send_sticker(message.chat.id, sti)

@bot.message_handler(regexp="(?=.*(are you|name))(?=.*(who|what))")
def name(message):
    bot.reply_to(message, "I am your Medical Assistant")

@bot.message_handler(func=lambda
        message: message.text is not None and 'hi' in message.text.lower() or message.text is not None and 'hello' in message.text.lower())
def wel(message):
    bot.reply_to(message,
                 'Hello ' + message.from_user.first_name + '. Welcome to MedicalBot using pyTelegramBotAPI.How can i help you?🙂')

@bot.message_handler(commands=['start'])
def send_welcome(message):
    bot.reply_to(message, 'Welcome!I am active as ever.Go ahead and ask me your Queries.')
    file_id = ['1.tgs', '2.webp', '3.tgs', '4.webp', '5.tgs', '6.tgs', '7.tgs']
    sti = open('stickers/hi/' + random.choice(file_id), 'rb')
    bot.send_sticker(message.chat.id, sti)

@bot.message_handler(commands=['help'])
def send_help(message):
    bot.reply_to(message,
                 "Here's the list of features in provide:\n/start-Activate me😋\n/desc-About me😍\n/medinfo-Health Info\npretty cool huh😎")

@bot.message_handler(commands=['medinfo'])
def send_m(message):
    bot.reply_to(message, 'Please send name of the disease to continue✌:\n/amru-send to know about Maa Amrutam Yojna')

@bot.message_handler(commands=['desc'])
def send_d(message):
    bot.reply_to(message,
                 'This bot was created to fulfill otherwordly http://www.magujarat.com/about-gujarati.html of E divsion.Proceed with caution.')

@bot.message_handler(func=lambda message: message.text is not None and 'how are you' in message.text.lower())
def sendd(message):
    bot.reply_to(message, "i've had an exciting day,looking up some fun things to do,What can i do for you🙂")

@bot.message_handler(func=lambda message: message.text is not None and 'flu' in message.text.lower())
def flu(message):
    bot.reply_to(message,
                 "The flu, also called influenza, is a respiratory infection caused by viruses. Sometimes it causes mild illness. But it can also be serious or even deadly, especially for people over 65, newborn babies, and people with certain chronic illnesses.\nFor more Information visit:Wiki",
                 parse_mode='HTML')

@bot.message_handler(func=lambda message: message.text is not None and 'diabetes' in message.text.lower())
def dia(message):
    bot.reply_to(message,
                 "Diabetes is a disease that occurs when your blood glucose, also called blood sugar, is too high. Blood glucose is your main source of energy and comes from the food you eat. Insulin, a hormone made by the pancreas, helps glucose from food get into your cells to be used for energy.\nFor more information visit:Wiki",
                 parse_mode='HTML')

@bot.message_handler(func=lambda message: message.text is not None and 'fever' in message.text.lower())
def fev(message):
    bot.reply_to(message,
                 "Fever is when a human's body temperature goes above the normal range of 36–37° Centigrade (98–100° Fahrenheit). It is a common medical sign. Other terms for a fever include pyrexia and controlled hyperthermia. As the body temperature goes up, the person may feel cold until it levels off and stops rising.\nFor more information visit:Wiki",
                 parse_mode='HTML')

@bot.message_handler(func=lambda
        message: message.text is not None and 'measure' in message.text.lower() and 'blood pressure' in message.text.lower())
def sendbp1(message):
    bot.reply_to(message,
                 'Unfortunately, I am physically unable to provide what you ask for🤷♂.But visiting a doctor would definitely help you😊.')

@bot.message_handler(func=lambda message: message.text is not None and 'what is blood pressure' in message.text.lower())
def sendbp(message):
    bot.reply_to(message,
                 "Blood pressure (BP) is the pressure of circulating blood on the walls of blood vessels. Most of this pressure is due to work done by the heart by pumping blood through the circulatory system.\nNormal resting blood pressure in an adult is approximately 120 millimetres of mercury (16 kPa) systolic, and 80 millimetres of mercury (11 kPa) diastolic, abbreviated 120/80 mmHg.\nFor more Information visit:Wiki",
                 parse_mode='HTML')

@bot.message_handler(regexp="(?=.*appetite)(?=.*(loss|decrease))")
def lapp(message):
    bot.reply_to(message,
                 "Lack of appetite, or decreased hunger, is one of the most troublesome nutrition problems you can experience. Although it is a common problem, its cause is unknown. There are some medicines that might stimulate your appetite. Ask your doctor if such medicines would help you.\n*Solutions:-*\n~Eat smaller meals and snacks more frequently.\n~Eating six or seven or eight times a day might be more easily tolerated than eating the same amount of food in three meals.\n~Talk to your doctor. Sometimes, poor appetite is due to depression, which can be treated. Your appetite is likely to improve after depression is treated.\n~Avoid non-nutritious beverages such as black coffee and tea.\n~Try to eat more protein and fat, and less simple sugars.\n~Walk or participate in light activity to stimulate your appetite.",
                 parse_mode="Markdown")

@bot.message_handler(regexp="(?=.*weight)(?=.*(loss|decrease))")
def lwei(message):
    bot.reply_to(message,
                 'If your doctor tells you that you have lost too much weight, or if you are having difficulty maintaining a healthy weight, here are some tips:\n=>Drink milk or try  "high-calorie recipes"  instead of drinking low-calorie beverages.\n=>Ask your doctor or dietitian about nutritional supplements. Sometimes, supplements in the form of snacks, drinks (such as Ensure® or Boost®), or vitamins might be prescribed to eat between meals. These supplements help you increase your calories and get the right amount of nutrients every day. Note: Do not use supplements in place of your meals.\n=>Avoid low-fat or low-calorie products unless you have been given other dietary guidelines. Use whole milk, whole milk cheese, and yogurt.\n=>Use the "*Calorie Boosters*"  to add calories to your favorite foods.',
                 parse_mode="Markdown")

@bot.message_handler(regexp="(?=.*anemia)(?=.*(what|mean|how))")
def ane(message):
    bot.reply_to(message,
                 "Anemia is a condition in which you lack enough healthy red blood cells to carry adequate oxygen to your body's tissues. Having anemia can make you feel tired and weak. There are many forms of anemia, each with its own cause. Anemia can be temporary or long term, and it can range from mild to severe.\nFor more Information visit:Click Here",
                 parse_mode='HTML')

@bot.message_handler(regexp="(?=.*arthritis)(?=.*(what|mean|how))")
def art(message):
    bot.reply_to(message,
                 "Arthritis means joint inflammation, but the term is used to describe around 200 conditions that affect joints, the tissues that surround the joint, and other connective tissue. It is a rheumatic condition. The most common form of arthritis is osteoarthritis.\nFor more Information visit:Click Here",
                 parse_mode='HTML')

@bot.message_handler(regexp="(?=.*cancer)(?=.*(what|mean|how))")
def can(message):
    keyboard = telebot.types.InlineKeyboardMarkup()
    keyboard.add(telebot.types.InlineKeyboardButton('Visit the page',
                                                    url='https://www.medicalnewstoday.com/articles/323648.php'))
    bot.reply_to(message,
                 "Cancer is a group of diseases involving abnormal cell growth with the potential to invade or spread to other parts of the body. These contrast with benign tumors, which do not spread.\nFor more Information visit:Click Here",
                 parse_mode="HTML", reply_markup=keyboard)
@bot.message_handler(regexp="(?=.*bp)(?=.*(what|mean|how))")
def sendbp1(message):
    bot.reply_to(message,
                 "Blood pressure (BP) is the pressure of circulating blood on the walls of blood vessels. Most of this pressure is due to work done by the heart by pumping blood through the circulatory system.\nNormal resting blood pressure in an adult is approximately 120 millimetres of mercury (16 kPa) systolic, and 80 millimetres of mercury (11 kPa) diastolic, abbreviated 120/80 mmHg.\nFor more Information visit:Wiki",
                 parse_mode='HTML')
@bot.message_handler(func=lambda message: message.text is not None and 'what is bmi' in message.text.lower())
def send1(message):
    '''keyboard = telebot.types.InlineKeyboardMarkup()
    keyboard.row(
    telebot.types.InlineKeyboardButton('Yes!', callback_data='get-yes'),
    telebot.types.InlineKeyboardButton('No!', callback_data='get-no')
    )'''
    msg = bot.reply_to(message,
                       "Body Mass Index(BMI) is a measurement of a person's leanness or corpulence based on their height and weight, and is intended to quantify tissue mass. It is widely used as a general indicator of whether a person has a healthy body weight for their height. Specifically, the value obtained from the calculation of BMI is used to categorize whether a person is underweight, normal weight, overweight, or obese depending on what range the value falls between.Do you want to calculate your BMI?🧐")
    bot.register_next_step_handler(msg, send2)

'''@bot.callback_query_handler(func=lambda call: True)
def callback_query(call):
    if call.data == "get-yes":
        bot.answer_callback_query(call.id, "Answer is Yes")
    elif call.data == "get-no":
        bot.answer_callback_query(call.id, "Answer is No")'''

def send2(message):
    if message.text.lower() == 'yes':
        bot.reply_to(message,
                     'BMI Calculator',
                     parse_mode='HTML')
    elif message.text.lower() == 'no':
        bot.reply_to(message, 'Have fun😄')
    else:
        bot.reply_to(message, 'Well, that was unexpected!')

@bot.message_handler(commands=['amru'])
def amru_hand(message):
    keyboard = telebot.types.InlineKeyboardMarkup()
    keyboard.add(telebot.types.InlineKeyboardButton('Click Here', url='http://www.magujarat.com/about-gujarati.html'))
    bot.send_message(message.chat.id, 'Ma Amrutam Yojna Website', reply_markup=keyboard)

@bot.message_handler(content_types=['text'])
def unrec(message):
    bot.send_message(message.chat.id, "Sorry! I wasn't able to recognize what you sent.Please try again")

bot.polling(none_stop=True)


import json

if __name__ == "__main__":

    questions_path = "C:/Users/benjavides/Desktop/Relation-Network-PyTorch/data/miniGQA/testing_question_ids.json"

    with open(questions_path, "r") as f:
        questions = json.load(f)

    yes=0
    no=0
    other=0

    for image_id in questions:
        question_dict = questions[image_id]
        answer = question_dict["answer"]
        if answer == "yes":
            yes+=1
        elif answer == "no":
            no+=1
        else:
            other+=1

    total = yes+no+other
    print(f"yes:{yes} no:{no} other:{other}")
    print(f"yes:{yes*100/total} no:{no*100/total} other:{other*100/total}")
#yes:41.828 no:56.558 other:28.898


# !/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author: Marco
# @Date:   2016-04-17 14:40:30
# @Last Modified by:   Marco
# @Last Modified time: 2016-04-18 11:54:18

"""
Created on Sun Apr 17 15:17:17 2016

@author: Marco
"""

import argparse
# import scipy
import numpy
import pandas as pd

def parser_function():
    '''
    Function to parse arguments
    '''
    parser = argparse.ArgumentParser(description='''This program gets a
         text file with species names as input to create a taxonomic query on
         NCBI and retrieve taxonomic levels that have a defined Rank on NCBI
        ''')
    # Adding an argument to 'parse'
    parser.add_argument('in_file', type=str,
                        help='type the name and path of the input csv file')
    parser.add_argument('parameters', type=str,
                        help='path to txt file containing the parameters')
    parser.add_argument('out_file', type=str,
                        help='type the name and path of the output csv file')
    args = parser.parse_args()
    inp = args.in_file
    parameters = args.parameters
    outp = args.out_file
    return inp, parameters, outp

def text_to_list(txt_file):
    parameters = []
    with open(txt_file, 'r') as f:
        for line in f:
            parameters.append(line.strip("\n"))
    return parameters

def ci(df): return df.quantile(q=0.95)

def pivotation(amniotes, parameters):
    mean = pd.pivot_table(amniotes, values=parameters,
                          index=['class', 'order'], aggfunc=numpy.mean)
    mean.insert(0, column="Parameter",
                value="MEAN", allow_duplicates=True)
    minimum = pd.pivot_table(amniotes, values=parameters,
                             index=['class', 'order'], aggfunc=numpy.min)
    minimum.insert(0, column="Parameter",
                   value="MINIMUM", allow_duplicates=True)
    maximum = pd.pivot_table(amniotes, values=parameters,
                             index=['class', 'order'], aggfunc=numpy.max)
    maximum.insert(0, column="Parameter",
                   value="MAXIMUM", allow_duplicates=True)
    median = pd.pivot_table(amniotes, values=parameters,
                            index=['class', 'order'], aggfunc=numpy.median)
    median.insert(0, column="Parameter",
                  value="MEDIAN", allow_duplicates=True)
    ci95 = pd.pivot_table(amniotes, values=parameters,
                          index=['class', 'order'], aggfunc=ci)
    ci95.insert(0, column="Parameter",
                value="CI95", allow_duplicates=True)
    concate = mean.append([minimum, maximum, median, ci95])
    classes = []
    orders = []
    for x in concate.index:
        classes.append(x[0])
        orders.append(x[1])
    concate.insert(0, "Class", classes)
    concate.insert(1, "Order", orders)
    concate['index'] = list(range(len(concate)))
    concate = concate.set_index('index')
    return concate

def main():
    input_csv, parameters, output_csv = parser_function()
    amniotes = pd.read_csv(input_csv)
    amniotes = amniotes.replace(-999, numpy.nan)
    amniotes = amniotes.replace(float(-999), numpy.nan)
    amniotes = amniotes.replace(str(-999), numpy.nan)
    parameters = text_to_list(parameters)
    concate = pivotation(amniotes, parameters)
    concate.to_csv(output_csv)

if __name__ == '__main__':
    main()


import graphene
from flask import g

from stronk.schemas.workout.type import Workout
from stronk.schemas.workout_exercise.type import WorkoutExercise as WorkoutExercise

from stronk.models.program import Program as ProgramModel
from stronk.models.program_workouts import ProgramWorkouts as ProgramWorkoutsModel
from stronk.models.workout import Workout as WorkoutModel
from stronk.models.workout_exercise import WorkoutExercise as WorkoutExerciseModel
from stronk.utils.date import date_time_str_to_date
from stronk.utils.auth import is_authorized

class CreateWorkout(graphene.Mutation):
    """ creates a workout and adds it to a program - result is the new workout
    """
    # mutation results
    workout = graphene.Field(Workout)

    class Arguments:
        name = graphene.String(required=True)
        description = graphene.String(required=False)
        projected_time = graphene.Int(required=False)
        program_id = graphene.Int(required=True)
        scheduled_time = graphene.String(required=True)

    def mutate(root, info, name: str, program_id: int, scheduled_time: str, description: str = None, projected_time: int = None):
        program = ProgramModel.find_by_id(program_id)
        # convert date time string to datetime object
        formatted_time = date_time_str_to_date(scheduled_time)

        workout = WorkoutModel.create(author=g.id,
                                      name=name,
                                      description=description,
                                      projected_time=projected_time,
                                      scheduled_time=formatted_time)

        program_workout = ProgramWorkoutsModel.create(program_id=program.id,
                                                      workout_id=workout.id)
        return CreateWorkout(workout=workout)

class UpdateWorkout(graphene.Mutation):
    """ updates a workout's information
    """
    # mutation results
    workout = graphene.Field(Workout)

    class Arguments:
        id = graphene.Int(required=True)
        name = graphene.String(required=False)
        description = graphene.String(required=False)
        projected_time = graphene.Int(required=False)
        scheduled_time = graphene.String(required=False)

    def mutate(root, info, id: str, name: str = None, description: str = None, projected_time: int = None, scheduled_time: str = None):
        workout = WorkoutModel.find_by_id(id)
        is_authorized(workout.author)

        attrs = {}
        if name:
            attrs['name'] = name
        if description:
            attrs['description'] = description
        if projected_time:
            attrs['projected_time'] = projected_time
        if scheduled_time:
            attrs['scheduled_time'] = date_time_str_to_date(scheduled_time)

        workout.update(attrs)

        return UpdateWorkout(workout=workout)

class DeleteWorkout(graphene.Mutation):
    """ removes a workout from a program
    """
    # mutation results
    ok = graphene.Boolean()

    class Arguments:
        id = graphene.Int()

    def mutate(root, info, id):
        workout = WorkoutModel.find_by_id(id)
        is_authorized(workout.author)
        # delete workout exercises associated with this workout
        WorkoutExerciseModel.deleteWorkoutExercises(id)

        # each workout should be unique to a program
        program_workout = ProgramWorkoutsModel.find_by_workout_id(id)
        program_workout.delete()

        workout.delete()
        ok = True

        return DeleteWorkout(ok=ok)

class Mutation(graphene.ObjectType):
    create_workout = CreateWorkout.Field()
    update_workout = UpdateWorkout.Field()
    delete_workout = DeleteWorkout.Field()


from .models import Server, Hero, Role, UserProfile
from rest_framework.serializers import ModelSerializer, ValidationError,SlugRelatedField
class ServerSerializer(ModelSerializer):
    class Meta:
        model = Server
        fields = '__all__'

class RoleSerializer(ModelSerializer):
    class Meta:
        model = Role
        fields = '__all__'

class HeroSerializer(ModelSerializer):
    class Meta:
        model = Hero
        fields = '__all__'

class UserProfileSerializer(ModelSerializer):
    fav_servers = SlugRelatedField(
        many=True,
        queryset=Server.objects.all(),
        slug_field='name',
    )

    fav_roles = SlugRelatedField(
        many=True,
        queryset=Role.objects.all(),
        slug_field='name',
    )

    fav_heroes = SlugRelatedField(
        many=True,
        queryset=Hero.objects.all(),
        slug_field='name',
    )
    def validate_fav_servers(self, value):
        if len(value) > 3:
            raise ValidationError("Too many servers selected, maximum is 3")
        return value

    def validate_fav_heroes(self, value):
        if len(value) > 5:
            raise ValidationError("Too many heroes selected, maximum is 5")
        return value

    def validate_fav_roles(self, value):
        if len(value) > 3:
            raise ValidationError("Too many roles selected, maximum is 3")
        return value
    # check if the user is logged in
    def validate_user(self, value):
        if self.context.get('request'):
              if self.context['request'].user != value:
                raise ValidationError("You do not have the permission to create or this resource")
        else:
            raise ValidationError("Login?")
        return value
    class Meta:
        model = UserProfile
        fields = ('fav_servers', 'fav_heroes', 'id', 'fav_roles')


# taken from https://github.com/pytorch/examples/blob/master/mnist/main.py
import argparse
import torch
from torch import nn
from torch.nn import functional as F
from torch import optim
from torchvision import datasets, transforms
from torch.autograd import Variable

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 10, kernel_size=5)
        self.conv2 = nn.Conv2d(10, 20, kernel_size=5)
        self.conv2_drop = nn.Dropout2d()
        self.fc1 = nn.Linear(320, 50)
        self.fc2 = nn.Linear(50, 10)

    def forward(self, x):
        x = F.relu(F.max_pool2d(self.conv1(x), 2))
        x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))
        x = x.view(-1, 320)
        x = F.relu(self.fc1(x))
        x = F.dropout(x, training=self.training)
        x = self.fc2(x)
        return F.log_softmax(x, dim=1)

def train(args, kwargs):
    torch.manual_seed(args.seed)
    if args.cuda:
        torch.cuda.manual_seed(args.seed)

    train_loader = torch.utils.data.DataLoader(
        datasets.MNIST('./data', train=True, download=True,
                       transform=transforms.Compose([
                           transforms.ToTensor(),
                           transforms.Normalize((0.1307,), (0.3081,))
                       ])),
        batch_size=args.batch_size, shuffle=True, **kwargs)

    model = Net()
    if args.cuda:
        model.cuda()

    optimizer = optim.SGD(model.parameters(), lr=args.lr,
                          momentum=args.momentum)

    for epoch in range(1, args.epochs+1):
        model.train()
        for batch_idx, (data, target) in enumerate(train_loader):
            if args.cuda:
                data, target = data.cuda(), target.cuda()
            data, target = Variable(data), Variable(target)
            optimizer.zero_grad()
            output = model(data)
            loss = F.nll_loss(output, target)
            loss.backward()
            optimizer.step()
            if batch_idx % args.log_interval == 0:
                print('Train Epoch: {}[{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                    epoch, batch_idx*len(data), len(train_loader.dataset),
                    100. * batch_idx/len(train_loader), loss.data[0]))

    return model

def test(args, kwargs, model):
    model.eval()
    test_loss = 0
    correct = 0
    test_loader = torch.utils.data.DataLoader(
        datasets.MNIST('./data', train=False, transform=transforms.Compose([
            transforms.ToTensor(),
            transforms.Normalize((0.1307,), (0.3081,))
        ])),
        batch_size=args.test_batch_size, shuffle=True, **kwargs)
    for data, target in test_loader:
        if args.cuda:
            data, target = data.cuda(), target.cuda()
        data, target = Variable(data, volatile=True), Variable(target)
        output = model(data)
        test_loss += F.nll_loss(output, target, size_average=False).data[0]
        pred = output.data.max(1, keepdim=True)[1]
        correct += pred.eq(target.data.view_as(pred)).long().cpu().sum()

    test_loss /= len(test_loader.dataset)
    print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
        test_loss, correct, len(test_loader.dataset),
        100. * correct / len(test_loader.dataset)))

def parse_argument():
    parser = argparse.ArgumentParser(description="PyTorch MNIST Example")
    parser.add_argument('--batch_size', type=int, default=64,
                        metavar='N', help='input batch size for training')
    parser.add_argument('--test_batch_size', type=int, default=1000,
                        metavar='N', help='input batch size for testinf')
    parser.add_argument('--epochs', type=int, default=10,
                        metavar='N', help='number of epochs to train')
    parser.add_argument('--lr', type=float, default=0.01,
                        metavar='LR', help='learning rate')
    parser.add_argument('--momentum', type=float, default=0.5,
                        metavar='M', help='SGD momentum')
    parser.add_argument('--no-cuda', action='store_true',
                        default=False, help='disable CUDA training')
    parser.add_argument('--seed', type=int, default=1,
                        metavar='S', help='random seed')
    parser.add_argument('--log_interval', type=int, default=10, metavar='N',
                        help='how many batches to wait before logging training status')
    args = parser.parse_args()
    args.cuda = not args.no_cuda and torch.cuda.is_available()
    return args

def main():
    args = parse_argument()
    kwargs = {'num_workers': 1, 'pin_memory': True} if args.cuda else {}
    trained_model = train(args, kwargs)
    test(args, kwargs, trained_model)

if __name__ == '__main__':
    main()


from operator import attrgetter

import pytest

from regionmask import Regions, defined_regions
from regionmask.defined_regions import _maybe_get_column

from . import has_cartopy, requires_cartopy
from .utils import (
    REGIONS,
    REGIONS_DEPRECATED,
    REGIONS_REQUIRING_CARTOPY,
    get_naturalearth_region_or_skip,
)

def _test_region(region, n_regions):
    assert isinstance(region, Regions)
    assert len(region) == n_regions

    # currently all regions are -180..180
    assert region.lon_180

@pytest.mark.parametrize("region_name, n_regions", REGIONS.items())
def test_defined_region(region_name, n_regions):

    region = attrgetter(region_name)(defined_regions)

    _test_region(region, n_regions)

@pytest.mark.parametrize("region_name, n_regions", REGIONS_DEPRECATED.items())
def test_defined_region_deprecated(region_name, n_regions):

    region = attrgetter(region_name)(defined_regions)

    _test_region(region, n_regions)

@requires_cartopy
@pytest.mark.parametrize("region_name, n_regions", REGIONS_REQUIRING_CARTOPY.items())
def test_defined_regions_natural_earth(monkeypatch, region_name, n_regions):

    region = get_naturalearth_region_or_skip(monkeypatch, region_name)

    _test_region(region, n_regions)

@requires_cartopy
def test_natural_earth_loaded_as_utf8():
    # GH 95
    regions = defined_regions.natural_earth.ocean_basins_50
    r = regions[90]

    assert r.name == "Río de la Plata"

def test_maybe_get_column():
    class lowercase:
        @property
        def name(self):
            return 1

    class uppercase:
        @property
        def NAME(self):
            return 2

    assert _maybe_get_column(lowercase(), "name") == 1
    assert _maybe_get_column(uppercase(), "name") == 2
    assert _maybe_get_column(uppercase(), "NAME") == 2

    with pytest.raises(KeyError, match="not on the geopandas dataframe"):
        _maybe_get_column(lowercase, "not_a_column")

@pytest.mark.skipif(has_cartopy, reason="should run if cartopy is _not_ installed")
def test_natural_earth_raises_without_cartopy():

    with pytest.raises(ImportError, match="cartopy is required"):
        defined_regions.natural_earth.countries_110


import os
from inspect import getmembers
from jinja2 import Markup
from flask import Flask, jsonify, render_template
from flask_jwt_extended import JWTManager
from flask_cache import Cache
from application import config

TEMPLATE_DIR = os.path.dirname(os.path.abspath(__file__))
if not config.USE_REDIS:
    cache = Cache(config={'CACHE_TYPE': 'simple'})
if not config.USE_CACHE:
    cache = Cache(config={'CACHE_TYPE': 'null'})
else:
    cache = Cache(config=config.REDIS_CONFIG)

# Bundle app creation in a function for use with testing and easier config
def create_app(app_config=None):
    global cache
    if app_config:
        for member in getmembers(app_config):
            setattr(config, member[0], member[1])
    # Initialize application, DB, and cache
    app = Flask(__name__)
    app.config.from_object(config)

    with app.app_context():
        # Initialize DB
        from application.base_models import db
        db.init_app(app)
        if config.USE_GEVENT:
            db.engine.pool._use_threadlocal = True
            db.engine.pool.use_threadlocal = True
        # register the cache to the app
        cache.init_app(app)

        from application.exceptions import InvalidAPIRequest, get_traceback
        from application.auth.auth_utilities import JWTUtilities
        # Initialize JWT handler
        jwt = JWTManager(app)

        @jwt.user_claims_loader
        def add_use_claims(user):
            return JWTUtilities.add_user_claims(user)

        @jwt.user_identity_loader
        def get_user_identity(user):
            return JWTUtilities.get_user_identity(user)

        # Initializing Routes/Modules
        from application.controllers import home_blueprint
        from application.auth.controllers import auth_blueprint
        from application.recipe.controllers import recipe_blueprint
        from application.user.controllers import user_blueprint
        from application.admin.controllers import admin_blueprint
        blueprints = [
            home_blueprint,
            auth_blueprint,
            recipe_blueprint,
            user_blueprint,
            admin_blueprint
        ]

        for blueprint in blueprints:
            setattr(blueprint, 'template_folder',
                    os.path.join(
                        TEMPLATE_DIR,
                        blueprint.template_folder
                    ))
            app.register_blueprint(blueprint)

        # for serving static admin pages
        app.jinja_env.globals['include_raw'] = lambda filename: Markup(app.jinja_loader.get_source(app.jinja_env, filename)[0])

        # Initialize general API Error handler function
        @app.errorhandler(Exception)
        def handle_api_error(error):
            db.session.remove()
            if isinstance(error, InvalidAPIRequest):
                if error.status_code != 404:
                    if error.status_code == 500 and config.DEBUG:
                        print(get_traceback())
                    response = jsonify(error.to_dict())
                    response.status_code = error.status_code
                    return response
                return render_template('404.html')
            else:
                app.logger.error("Unknown error: {0}. Stacktrace: {1}".format(str(error), get_traceback()))

        # Teardown to close/dremove db sessions after requests
        @app.teardown_appcontext
        def remove_session(exception=None):
            db.session.remove()

        return app


#! /usr/bin/env python

import os
import sys
import json
from uuid import uuid4
import logging
import socket
from os import path
from functools import wraps
from subprocess import Popen, PIPE
import datetime

from flask import Flask, request, make_response
from flask import render_template
from flask import g
from jinja2 import ChoiceLoader, FileSystemLoader
from werkzeug import secure_filename
from werkzeug.http import http_date
from werkzeug.routing import Submount, Map

from . import messages

STATIC_DIR = os.environ.get('STATIC_DIR', path.join(os.getcwd(), 'static'))
TEMPLATE_DIR = os.environ.get('TEMPLATE_DIR', path.join(os.getcwd(), 'templates'))
app = Flask(__name__, static_folder=STATIC_DIR, template_folder=TEMPLATE_DIR)

app.config['VERSION'] = os.environ.get('CURRENT_SHA', None)
app.config['X-HOSTNAME'] = os.environ.get('X_HOSTNAME', socket.gethostname())
app.config['BIND_INTERFACE'] = os.environ.get('BIND_INTERFACE', '127.0.0.1')
app.config['LOG_LEVEL'] = os.environ.get('LOG_LEVEL', 'INFO')
app.config['USER_HEADER_NAME'] = os.environ.get('USER_HEADER_NAME', 'Uid')
app.config['ROOT_STORAGE_PATH'] = os.environ.get("ROOT_STORAGE_PATH", "./storage")
app.config['CACHE_ROOT'] = os.environ.get('CACHE_ROOT', '%s/cache' % (app.config['ROOT_STORAGE_PATH']))
app.config['USE_RELOADER'] = os.environ.get('USE_RELOADER', 'True')
app.config['TEMPLATE_DIR'] = TEMPLATE_DIR
app.config['SUBMOUNT_PATH'] = os.environ.get('SUBMOUNT_PATH', None)
# this is to be a comman delimited list of sources for which events will be emitted
# this of course depends on the system supporting events for those sources
app.config['LOCAL_EVENT_SOURCES'] = frozenset(os.environ.get('LOCAL_EVENT_SOURCES', '').split(","))

app.jinja_loader = ChoiceLoader([
        FileSystemLoader("./templates"),
        FileSystemLoader("./pyserver/templates")
    ])

logging.basicConfig(
    format='%(asctime)s [%(levelname)s]: %(message)s',
    stream=sys.stderr,
    level=app.config['LOG_LEVEL']
)

process_start_time = datetime.datetime.now()

def emit_local_message(source, message=None):
    if source in app.config['LOCAL_EVENT_SOURCES']:
        wrapped = json.dumps(dict(source=source, message=message, user_token=g.user_token))
        messages.send(wrapped, messages.LOCAL_PUBLISH)

def get_storage_location(named):
    return path.abspath(path.join(app.config['ROOT_STORAGE_PATH'], named))

def remove_single_element_lists(d):
    new_dict = {}
    for key, value in list(d.items()):
        if type(value) == list and len(value) == 1:
            new_dict[key] = value[0]
        else:
            new_dict[key] = value
    return new_dict

def try_run(this):
    try:
        return this()
    except:
        return None

def convert_into_number(value):
    as_number = try_run(lambda: int(value)) or try_run(lambda: float(value))
    if as_number or as_number == 0:
        return as_number
    else:
        return value

def convert_types_in_dictionary(this_dictionary):
    into_this_dictionary = {}
    for key, value in list(this_dictionary.items()):
        if type(value) == dict:
            value = convert_types_in_dictionary(value)
        elif type(value) == list:
            value = convert_types_in_list(value)
        else:
            value = convert_into_number(value)
        into_this_dictionary[key] = value
    return into_this_dictionary

def convert_types_in_list(this_list):
    into_this_list = []
    for item in this_list:
        if type(item) == list:
            new_value = convert_types_in_list(item)
        elif type(item) == dict:
            new_value = convert_types_in_dictionary(item)
        else:
            new_value = convert_into_number(item)
        into_this_list.append(new_value)
    return into_this_list

def cache_my_response(vary_by=None, expiration_seconds=900):
    def cache_wrapper_decorator(f):
        @wraps(f)
        def cache_wrapper(*args, **kwargs):
            if not vary_by:
                cache_key = request.url
            else:
                from io import StringIO
                key_buffer = StringIO()
                key_buffer.write(request.url)
                for vary_by_this in vary_by:
                    key_buffer.write("%s" % request.values.get(vary_by_this, ''))
                cache_key = key_buffer.getvalue()
            cr = app.config['_CACHE'].get_or_return_from_cache(
                cache_key,
                expiration_seconds,
                lambda: f(*args, **kwargs),
                force_refresh = request.values.get('_reload_cache', False)
            )
            resp = app.make_response(cr[1])
            if cr[0]:
                resp.headers['Expires'] = http_date(cr[0])
            return resp
        return cache_wrapper
    return cache_wrapper_decorator

def make_my_response_json(f):
    @wraps(f)
    def view_wrapper(*args, **kwargs):
        try:
            view_return = f(*args, **kwargs)
            if type(view_return) == dict:
                return json_response(**view_return)
            elif type(view_return) == list:
                return json_response(view_return)
            elif type(view_return) == int:
                return json_response(**dict(status_code=view_return))
            elif type(view_return) == str:
                return json_response(view_return)
            elif type(view_return) == tuple:
                return json_response(view_return[0], status_code=view_return[1])
            else:
                return json_response(**{})
        except Exception as e:
            return json_response(**dict(status_code=400, description=e.description))
    return view_wrapper

def json_response(*args, **kwargs):
    """ Creates a JSON response for the given params, handling the creation a callback wrapper
        if a callback is provided, and allowing for either a string arg (expected to be JSON)
        or kwargs to be passed formatted correctly for the response.
        Also sets the Content-Type of the response to application/json
    """
    content_type = "application/json"
    # if provided, use the status code otherwise default to 200
    # we remove it so it doesn't end up in our response
    status_code = kwargs.pop('status_code', 200)

    # we're going to allow the callback to come essentially from wherever the user
    # choses to provide it, again remove it from kwargs so it doesn't end
    # up in the response
    callback = kwargs.pop('callback', None) or request.values.get('callback', None)

    # handle the response being a list of items
    if args:
        if type(args[0]) == list:
            response_string = json.dumps(args[0])
        # if the return is a string assume it's valid json
        elif type(args[0]) == str:
            response_string = json.dumps(args[0]) if callback else args[0]
    else:
        response_string = json.dumps(kwargs)

    if callback:
        response_string = "%s(%s);" % (callback, response_string)
        content_type = "application/javascript"
        # I know it's sucky but many clients will fail on jsonp requests
        # that return a 404
        if status_code == 404:
            status_code = 200

    headers = {"Content-Type": content_type, "Cache-Control": "no-cache", "Pragma": "no-cache"}

    return (
        response_string,
        status_code,
        headers
    )

def return_cors_response():
    headers = dict()
    headers['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS, DELETE, PATCH'
    headers['Access-Control-Allow-Headers'] = request.headers.get('Access-Control-Request-Headers', '*')
    return ( "", 204, headers )

def global_response_handler(response):
    response.headers['Access-Control-Allow-Origin'] = request.headers.get('Origin', '*')
    response.headers['Access-Control-Allow-Credentials'] = 'true'
    response.headers['X-HOSTNAME'] = app.config['X-HOSTNAME']
    response.headers['X-APP-VERSION'] = app.config['VERSION']
    return response

def global_request_handler():
    # this needs to be safe for use by the app
    g.user_token = secure_filename(request.headers.get(app.config['USER_HEADER_NAME'], 'DEFAULT'))

app.process_response = global_response_handler
app.preprocess_request = global_request_handler

################################################################################
# views

@app.route("/", methods=["GET"])
@app.route("/diag", methods=["GET"])
@app.route("/diagnostic", methods=["GET"])
def pyserver_core_diagnostic_view():
    """
        Used to return the status of the application, including the version
        of the running application.

        :statuscode 200: returned as long as all checks return healthy
        :statuscode 500: returned in the case of any diagnostic tests failing
    """
    diag_info = {}
    diag_info['machine_name'] = socket.gethostname()
    diag_info['process_start_time'] = process_start_time.isoformat()
    diag_info['process_uptime_secs'] = (datetime.datetime.now() - process_start_time).seconds
    diag_info['server_port'] = os.environ.get('PORT', None)

    response = make_response(json.dumps(diag_info, sort_keys=True))
    response.headers['X-Robots-Tag'] = 'noindex'
    return response

@app.route("/diagnostic/echo", methods=["GET"])
@make_my_response_json
def pyserver_core_diagnostic_echo_view():
    """
        Helper endpoint for developing diagnostic checks.  Simply echoes back
        any values provided in the inbound request.

        :param '*': any inbound request parameters will be echoed back
        :statuscode 200: always returns OK
    """
    return request.values.to_dict()

@app.route("/diagnostic/fail", methods=["GET"])
def pyserver_core_fail():
    """ This endpoint is designed to show how the application fails.  Can be used
        to assist in creating monitors to check the application health and respond
        to failures.

        :statuscode 500: always returns failure
    """
    raise Exception("Test exception so you know how the app behaves")

@app.route("/message/local_publish", methods=["POST"])
@make_my_response_json
def pyserver_core_publish_message():
    """ Allows for publishing of a local message.  """
    if request.json:
        msg = json.dumps(request.json)
    else:
        data = request.values.to_dict(flat=False)
        msg = convert_types_in_dictionary(remove_single_element_lists(data))
        msg = json.dumps(msg)
    messages.send(msg, messages.LOCAL_PUBLISH)
    return dict(message="ok")

# end views
################################################################################

@app.errorhandler(500)
def general_error_handler(error):
    et, ev, tb = sys.exc_info()
    assert ev == error
    eid = str(uuid4())
    logging.error("unhandled exception(%s):" % (eid), exc_info = (et, ev, tb))
    context = dict(eid=eid)
    if request.content_type and 'json' in request.content_type:
        return (render_template("500.json", **context),
            500,
            {"Content-Type": "application/json"})
    else:
        return render_template("500.html", **context), 500

from .core_handlers import keyvalue_handlers, echo


"""
    Tests for botogram/objects/messages.py

    Copyright (c) 2016 Pietro Albini <pietro@pietroalbini.io>
    Released under the MIT license
"""

import pytest

import botogram.objects.messages
import botogram.objects.chats

def get_dummy_message(text):
    """Get a dummy message with a custom text"""
    return botogram.objects.messages.Message({
        "message_id": 1,
        "from": {"id": 123, "first_name": "Nobody"},
        "chat": {"id": -123, "type": "chat", "title": "Something"},
        "date": 1,
        "text": text,
    })

def parsed_to_list(parsed):
    """Convert a ParsedText to a list of entities"""
    return [(e.type, e.text) for e in parsed]

###################
##  Parsed text  ##
###################

def test_parsed_text_entity():
    msg = get_dummy_message("Hey, I'm an http://url.com")

    # Try to create an entity without an attached message
    entity = botogram.objects.messages.ParsedTextEntity({
        "type": "url",
        "offset": 12,
        "length": 14,
    })
    assert entity.type == "link"
    # Those attributes requires a Message instance
    with pytest.raises(RuntimeError):
        entity.url
    with pytest.raises(RuntimeError):
        entity.text

    # Now attach a message
    entity.set_message(msg)
    assert entity.url == "http://url.com"
    assert entity.text == "http://url.com"

def test_parsed_text_entity_type():
    # Basic entity
    entity = botogram.objects.messages.ParsedTextEntity({
        "type": "",
        "offset": 0,
        "length": 23,
    })

    #################################
    #  A type which doesn't mutate  #
    #################################

    msg = get_dummy_message("#aaaaaaaaaaaaaaaaaaaaaaa")
    entity.set_message(msg)

    # Getter
    entity._type = "hashtag"
    assert entity.type == "hashtag"

    # Setter
    entity.type = "hashtag"
    assert entity._type == "hashtag"

    #########################
    #  A type which mutate  #
    #########################

    msg = get_dummy_message("/aaaaaaaaaaaaaaaaaaaaaaa")
    entity.set_message(msg)

    # Getter
    entity._type = "bot_command"
    assert entity.type == "command"

    # Setter
    entity.type = "command"
    assert entity._type == "bot_command"

    #####################################
    #  A link (which mutates as "url")  #
    #####################################

    msg = get_dummy_message("https://www.example.com")
    entity.set_message(msg)

    # Getter
    entity._type = "url"
    assert entity.type == "link"

    # Setter without URL explicitly defined
    entity.type = "link"
    assert entity._type == "url"

    # Setter with URL explicitly defined
    entity._url = "https://www.example.com"
    entity.type = "link"
    assert entity._type == "url"

    ###########################################
    #  A link (which mutates as "text_link")  #
    ###########################################

    msg = get_dummy_message("This is a labelled link")
    entity._url = "https://www.example.com"
    entity.set_message(msg)

    # Getter
    entity._type = "text_link"
    assert entity.type == "link"

    # Setter
    entity.type = "link"
    assert entity._type == "text_link"

    ############################################
    #  A mention (which mutates as "mention")  #
    ############################################

    msg = get_dummy_message("@test_image")
    entity.set_message(msg)

    # Getter
    entity._type = "mention"
    assert entity.type == "mention"

    # Setter
    entity.type = "mention"
    assert entity._type == "mention"

    #################################################
    #  A mention (which mutates as "text_mention")  #
    #################################################

    msg = get_dummy_message("@test_image")
    entity.user = botogram.objects.chats.User({"id": 1, "first_name": "Test"})
    entity.set_message(msg)

    # Getter
    entity._type = "text_mention"
    assert entity.type == "mention"

    # Setter
    entity.type = "mention"
    assert entity._type == "text_mention"

    entity.user = None

def test_parsed_text_entity_url():
    # Basic entity
    entity = botogram.objects.messages.ParsedTextEntity({
        "type": "",
        "offset": 0,
        "length": 23,
    })

    # Url entity
    msg = get_dummy_message("https://www.example.com")
    entity.type = "url"
    entity.set_message(msg)
    assert entity.url == "https://www.example.com"

    # Mention entity with @usernames
    msg = get_dummy_message("@a_botogram_users_group")
    entity.type = "mention"
    entity.set_message(msg)
    assert entity.url == "https://telegram.me/a_botogram_users_group"

    # Text mention entities without usernames
    msg = get_dummy_message("A botogram users group!")
    entity.user = botogram.objects.chats.User({"id": 1, "first_name": "Test"})
    entity.type = "mention"
    entity.set_message(msg)
    assert entity.url is None

    # Text mention entities with usernames
    entity.user.username = "test_username"
    assert entity.url == "https://telegram.me/test_username"

    entity.user = None

    # Email entity
    msg = get_dummy_message("john.42.doe@example.com")
    entity.type = "email"
    entity.set_message(msg)
    assert entity.url == "mailto:john.42.doe@example.com"

    # Non-url type with a forced url
    msg = get_dummy_message("this is not an url, obv")
    entity.type = "plain"
    entity._url = "https://www.example.com"
    entity.set_message(msg)
    assert entity.url == "https://www.example.com"
    entity._url = None

    # Url entity without a scheme
    msg = get_dummy_message("www.example.com/abcdefg")
    entity.type = "url"
    entity.set_message(msg)
    assert entity.url == "http://www.example.com/abcdefg"

def test_parsed_text():
    msg = get_dummy_message("This has an #hashtag!")
    parsed = botogram.objects.messages.ParsedText([
        {
            "type": "hashtag",
            "offset": 12,
            "length": 8,
        },
    ], message=msg)

    assert parsed_to_list(parsed) == [
        ("plain", "This has an "),
        ("hashtag", "#hashtag"),
        ("plain", "!"),
    ]
    assert parsed[0].text == "This has an "
    assert parsed[1].text == "#hashtag"
    assert parsed[2].text == "!"
    assert "plain" in parsed
    assert "hashtag" in parsed
    assert "url" not in parsed

def test_parsed_text_without_plain():
    # This needs an extra test because the "plain" types are not provided
    # directly by Telegram, but they're calculated dynamically by botogram
    msg = get_dummy_message("#hashtag")
    parsed = botogram.objects.messages.ParsedText([
        {
            "type": "hashtag",
            "offset": 0,
            "length": 8,
        },
    ], message=msg)

    assert parsed_to_list(parsed) == [
        ("hashtag", "#hashtag"),
    ]
    assert "plain" not in parsed

def test_parsed_text_filter():
    msg = get_dummy_message("I @mentioned #something!")
    parsed = botogram.objects.messages.ParsedText([
        {
            "type": "mention",
            "offset": 2,
            "length": 10,
        },
        {
            "type": "hashtag",
            "offset": 13,
            "length": 10,
        },
    ], message=msg)

    assert parsed_to_list(parsed) == [
        ("plain", "I "),
        ("mention", "@mentioned"),
        ("plain", " "),
        ("hashtag", "#something"),
        ("plain", "!"),
    ]
    assert parsed_to_list(parsed.filter("plain", "mention")) == [
        ("plain", "I "),
        ("mention", "@mentioned"),
        ("plain", " "),
        ("plain", "!"),
    ]
    assert parsed_to_list(parsed.filter("plain", exclude=True)) == [
        ("mention", "@mentioned"),
        ("hashtag", "#something"),
    ]


import os,sys,logging,datetime
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
import tensorflow
tensorflow.get_logger().setLevel(logging.ERROR)
from define_model import define_Morlet, define_2DR, define_RecR, define_1DCNN, load_tensorboard
from train_model import train_model
import numpy as np

#Directory: C:/Users/david/Documents/GitHub/exjobb/Testing Sets/final/subj(N)/(modellnamn)/(A/B/C)(Trialnummer)
n_subj = 18
models = {
#Tuple: (function,epochs,L,Fs,nchan)
#	"1DCNN":(define_1DCNN,40,820,512,62,"1DCNN"),
#	"Morlet":(define_Morlet,100,820,512,62,"Morlet"),
#	"ReassignmentRec":(define_RecR,30,193,256,31,"ReassignmentRec"),
#	"ReassignmentRecCorrect":(define_RecR,30,193,256,31,"ReassignmentRecCorrect"),
#	"SpectrogramRec":(define_RecR,30,193,256,31,"SpectrogramRec"),
#	"SpectrogramRecCorrect":(define_RecR,30,193,256,31,"SpectrogramRecCorrect"),
	"Spectrogram2D":(define_2DR,50,193,256,31,"Spectrogram2D"),
	"Reassignment2D":(define_2DR,50,193,256,31,"Reassignment2D")
}

histories = {
#	"1DCNN":np.zeros([models["1DCNN"][1],n_subj]),
#	"Morlet":np.zeros([models["Morlet"][1],n_subj]),
#	"ReassignmentRec":np.zeros([models["ReassignmentRec"][1],n_subj]),
#	"ReassignmentRecCorrect":np.zeros([models["ReassignmentRecCorrect"][1],n_subj]),
#	"SpectrogramRec":np.zeros([models["SpectrogramRec"][1],n_subj]),
#	"SpectrogramRecCorrect":np.zeros([models["SpectrogramRecCorrect"][1],n_subj]),
	"Spectrogram2D":np.zeros([models["Spectrogram2D"][1],n_subj]),
	"Reassignment2D":np.zeros([models["Reassignment2D"][1],n_subj])
}

for model in models:
	subjects = []
	for folder in os.listdir("C:/Users/Kioskar/Desktop/Testing exjobb/Albin_Damir/all_subj_crop/"+model+"/"):
		subjects.append(folder[4:6])
	print(subjects)
#	subjects = ["01","02"]
	print(subjects)
	print("Model: " + model + ", Epochs: " + str(models[model][1]))
	print("--------------------------------------------------------------------------")
	i = 0
	for subject in subjects:
		print("Subject: " + str(subject))
		date = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
		vals = np.array(train_model(models[model],subject,date))
		print(vals)
		histories[model][:,i] = np.mean(vals,axis=0)
		print(histories[model])
		i = i + 1
		print(np.sum(histories[model],axis=1)/np.sum(histories[model][0,:]>0))


# import the necessary packages
from __future__ import print_function
from batcountry import BatCountry
from PIL import Image
import numpy as np
import argparse
import warnings
import cv2

# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-b", "--base-model", required=True, help = "base model path")
ap.add_argument("-p", "--proto", required=False, help = "prototxt model path (default = 'deploy.prototxt')")		# added for the specific CNN prototxt
ap.add_argument("-m", "--caffe-model", required=False, help= "caffe model path (default = 'imagenet.caffemodel')")	# added for custom caffe-model
ap.add_argument("-it","--iter-n", required=False, default=10, type=int, help = "Number of iterations of the layer (default = 10)")
ap.add_argument("-oc","--octave-n", required=False, default=4, type=int,help = "Number of octaves (default = 4)")
ap.add_argument("-s","--octave-scale", required=False, type=float, default=1.4, help = "Scale of the octaves (default = 1.4)")
ap.add_argument("-l","--layer", required=False, type=str, default="conv3", help = "layer of CNN to use")
ap.add_argument("-i", "--image", required = True, help = "path to image file")
ap.add_argument("-o", "--output", required = True, help = "path to output directory")
args = ap.parse_args()

# filter warnings, initialize bat country, and grab the layer names of
# the CNN
warnings.filterwarnings("ignore")
bc = BatCountry(args.base_model,args.proto,args.caffe_model)

print("[INFO] processing layer `{}`".format(args.layer))
image = bc.dream(np.float32(Image.open(args.image)), iter_n=args.iter_n, octave_n=args.octave_n, end=args.layer)

# extract the filename and extension of the input image
filename = args.image[args.image.rfind("/") + 1:]
(filename, ext) = filename.split(".")

image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
cv2.putText(image, args.layer, (5, image.shape[0] - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.95, (0, 255, 0), 2)

# construct the output path and write the image to file
p = "{}/{}_{}_{}.{}".format(args.output, filename, args.layer, args.iter_n, ext) # instead of the pic index, writes the layer used
cv2.imwrite(p, image)

bc.cleanup();


import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

import collections
import json
import os

import numpy as np

class Vocab(object):
    '''Holding vocabulary.

    Core info:
        words: a list of words
        freqs: a list of frequencies
        unk_size: size of unknown words
        sample_factor: factor for (sub) sampling by rising frequency to this power.

    Infered:
        anything else :-D
    '''

    def __init__(self, counter=None, known_size=None, unk_size=1, sample_factor=3./4.):
        if counter is None:
            return
        if known_size is None:
            known_size = len(counter)
        assert known_size <= len(counter)

        most_common = counter.most_common(known_size)
        words, freqs = zip(*most_common)

        core = self.core = {
            'words': words,
            'freqs': freqs,
            'unk_size': unk_size,
            'sample_factor': sample_factor,
        }

        self._infer()

    def _infer(self):
        words = self.words = self.core['words']
        freqs = self.freqs = self.core['freqs']
        unk_size = self.unk_size = self.core['unk_size']
        sample_factor = self.sample_factor = self.core['sample_factor']

        known_size = self.known_size = len(words)
        vocab_size = self.vocab_size = known_size + unk_size
        logger.info('infer vocab with known_size = %d and unk_size = %d' % (
                self.known_size, self.unk_size))

        self.idx2str = self.words
        self.str2idx = {v:i for (i, v) in enumerate(self.idx2str)}

        weight = np.array(self.freqs, dtype=np.float32)
        weight = weight ** sample_factor
        weight = weight / weight.sum()
        weight_prefix_sum = [0.] * len(weight)
        weight_prefix_sum[0] = weight[0]
        for i in range(1, len(weight)):
            weight_prefix_sum[i] = weight[i] + weight_prefix_sum[i-1]
        self.weight = np.array(weight)
        self.weight_prefix_sum = np.array(weight_prefix_sum)

    def save(self, fp):
        if isinstance(fp, str):
            fp = open(fp, 'w')
        json.dump(self.core, fp)

    def load(self, fp):
        if isinstance(fp, str):
            fp = open(fp, 'r')
        self.core = json.load(fp)
        self._infer()

    def encode(self, obj):
        if isinstance(obj, list):
            return [self.encode(_) for _ in obj]
        elif isinstance(obj, str):
            index = self.str2idx.get(obj, -1)
            if index == -1:
                index = self.known_size + hash(obj) % self.unk_size
            return index
        else:
            assert False

    def decode(self, obj):
        if isinstance(obj, list):
            return [self.decode(_) for _ in obj]
        elif isinstance(obj, int):
            assert 0 <= obj < self.vocab_size
            if obj < self.known_size:
                return self.idx2str[obj]
            else:
                return 'unk_%d' % (obj - self.known_size)
        else:
            assert False

    def sample_single(self):
        p = np.random.rand()
        idx = np.searchsorted(self.weight_prefix_sum, p)
        idx = min(idx, self.known_size - 1)
        return idx

    def sample(self, num):
        return [self.sample_single() for _ in range(num)]

def test_vocab():
    import tempfile

    counter = collections.Counter(['a', 'a', 'b', 'b', 'b', 'c'])
    vocab = Vocab(counter, known_size=2, unk_size = 2)
    assert vocab.known_size == 2
    assert vocab.unk_size == 2
    assert vocab.vocab_size == 4
    assert vocab.encode('b') == 0
    assert vocab.encode('a') == 1
    assert vocab.encode(['a', 'b']) == [1, 0]
    assert vocab.decode(0) == 'b'
    assert vocab.decode(1) == 'a'
    assert vocab.decode([0, 1, 2, 3]) == ['b', 'a', 'unk_0', 'unk_1']

    sampled = vocab.sample(100)


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

import os
import sys
import argparse
from ruler import Ruler

def data_initialization(datafile):
    """ From a .txt file containing strings to compare, it creates a list of strings,
    without empty strings. This list has an even length"""

    with open(datafile) as f:
        lines = f.readlines()
        dataset = [y for y in [x.strip() for x in lines] if y != '']
        if len(dataset) % 2 != 0:
            dataset.pop()
    return dataset

def strings_comparison(str1 : str, str2 : str):
    """ Displays the distance and the alignments between 2 strings """

    ruler = Ruler(str1, str2)
    ruler.compute()
    print("======== distance = " + str(ruler.distance))
    top, bottom = ruler.report()
    print(top)
    print(bottom)

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("datafile", help="sequences to analyze")
    args = parser.parse_args()
    datafile = args.datafile
    dataset = data_initialization(datafile)
    for i in range(0, len(dataset), 2):
        strings_comparison(dataset[i], dataset[i + 1])
    return 0

if __name__ == '__main__':
    sys.exit(main())