import os
from PyQt5 import QtCore, QtGui, QtWidgets
from .presenter import MainWindowPresenter, MessageReplyType
from .dock_manager import DockManager
from .scene_manager import SceneManager
from sscanss.config import settings, path_for, DOCS_URL, __version__
from sscanss.ui.dialogs import (ProgressDialog, ProjectDialog, Preferences, AlignmentErrorDialog,
                                SampleExportDialog, ScriptExportDialog, PathLengthPlotter, AboutDialog)
from sscanss.ui.widgets import GLWidget, StatusBar, FileDialog
from sscanss.core.scene import Node
from sscanss.core.util import (Primitives, Directions, TransformType, PointType, MessageSeverity, Attributes,
                               toggleActionInGroup)

MAIN_WINDOW_TITLE = 'SScanSS 2'

class MainWindow(QtWidgets.QMainWindow):

    def __init__(self):
        super().__init__()

        self.recent_projects = []
        self.presenter = MainWindowPresenter(self)

        self.undo_stack = QtWidgets.QUndoStack(self)
        self.undo_view = QtWidgets.QUndoView(self.undo_stack)
        self.undo_view.setWindowTitle('History')
        self.undo_view.setAttribute(QtCore.Qt.WA_QuitOnClose, False)

        self.gl_widget = GLWidget(self)
        self.setCentralWidget(self.gl_widget)

        self.docks = DockManager(self)
        self.scenes = SceneManager(self)
        self.progress_dialog = ProgressDialog(self)
        self.about_dialog = AboutDialog(self)
        self.updater = Updater(self)

        self.createActions()
        self.createMenus()
        self.createToolBar()
        self.createStatusBar()

        self.setWindowTitle(MAIN_WINDOW_TITLE)
        self.setWindowIcon(QtGui.QIcon(path_for('logo.png')))
        self.setMinimumSize(1024, 900)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)

        self.readSettings()
        self.updateMenus()

    def createActions(self):
        self.new_project_action = QtWidgets.QAction('&New Project', self)
        self.new_project_action.setStatusTip('Create a new project')
        self.new_project_action.setIcon(QtGui.QIcon(path_for('file.png')))
        self.new_project_action.setShortcut(QtGui.QKeySequence.New)
        self.new_project_action.triggered.connect(self.showNewProjectDialog)

        self.open_project_action = QtWidgets.QAction('&Open Project', self)
        self.open_project_action.setStatusTip('Open an existing project')
        self.open_project_action.setIcon(QtGui.QIcon(path_for('folder-open.png')))
        self.open_project_action.setShortcut(QtGui.QKeySequence.Open)
        self.open_project_action.triggered.connect(self.openProject)

        self.save_project_action = QtWidgets.QAction('&Save Project', self)
        self.save_project_action.setStatusTip('Save project')
        self.save_project_action.setIcon(QtGui.QIcon(path_for('save.png')))
        self.save_project_action.setShortcut(QtGui.QKeySequence.Save)
        self.save_project_action.triggered.connect(lambda: self.presenter.saveProject())

        self.save_as_action = QtWidgets.QAction('Save &As...', self)
        self.save_as_action.setShortcut(QtGui.QKeySequence.SaveAs)
        self.save_as_action.triggered.connect(lambda: self.presenter.saveProject(save_as=True))

        self.export_samples_action = QtWidgets.QAction('Samples', self)
        self.export_samples_action.setStatusTip('Export samples')
        self.export_samples_action.triggered.connect(self.presenter.exportSamples)

        self.export_fiducials_action = QtWidgets.QAction('Fiducial Points', self)
        self.export_fiducials_action.setStatusTip('Export fiducial points')
        self.export_fiducials_action.triggered.connect(lambda: self.presenter.exportPoints(PointType.Fiducial))

        self.export_measurements_action = QtWidgets.QAction('Measurement Points', self)
        self.export_measurements_action.setStatusTip('Export measurement points')
        self.export_measurements_action.triggered.connect(lambda: self.presenter.exportPoints(PointType.Measurement))

        self.export_vectors_action = QtWidgets.QAction('Measurement Vectors', self)
        self.export_vectors_action.setStatusTip('Export measurement vectors')
        self.export_vectors_action.triggered.connect(self.presenter.exportVectors)

        self.export_alignment_action = QtWidgets.QAction('Alignment Matrix', self)
        self.export_alignment_action.setStatusTip('Export alignment matrix')
        self.export_alignment_action.triggered.connect(self.presenter.exportAlignmentMatrix)

        self.export_script_action = QtWidgets.QAction('Script', self)
        self.export_script_action.setStatusTip('Export script')
        self.export_script_action.triggered.connect(self.showScriptExport)

        self.exit_action = QtWidgets.QAction('E&xit', self)
        self.exit_action.setStatusTip(f'Quit {MAIN_WINDOW_TITLE}')
        self.exit_action.setShortcut(QtGui.QKeySequence.Quit)
        self.exit_action.triggered.connect(self.close)

        # Edit Menu Actions
        self.undo_action = self.undo_stack.createUndoAction(self, '&Undo')
        self.undo_action.setStatusTip('Undo the last action')
        self.undo_action.setIcon(QtGui.QIcon(path_for('undo.png')))
        self.undo_action.setShortcut(QtGui.QKeySequence.Undo)

        self.redo_action = self.undo_stack.createRedoAction(self, '&Redo')
        self.redo_action.setStatusTip('Redo the last undone action')
        self.redo_action.setIcon(QtGui.QIcon(path_for('redo.png')))
        self.redo_action.setShortcut(QtGui.QKeySequence.Redo)

        self.undo_view_action = QtWidgets.QAction('Undo &History', self)
        self.undo_view_action.setStatusTip('View undo history')
        self.undo_view_action.triggered.connect(self.showUndoHistory)

        self.preferences_action = QtWidgets.QAction('Preferences', self)
        self.preferences_action.setStatusTip('Change application preferences')
        self.preferences_action.triggered.connect(lambda: self.showPreferences(None))
        self.preferences_action.setShortcut(QtGui.QKeySequence('Ctrl+Shift+P'))

        # View Menu Actions
        self.solid_render_action = QtWidgets.QAction(Node.RenderMode.Solid.value, self)
        self.solid_render_action.setStatusTip('Render sample as solid object')
        self.solid_render_action.setIcon(QtGui.QIcon(path_for('solid.png')))
        self.solid_render_action.triggered.connect(lambda: self.scenes.changeRenderMode(Node.RenderMode.Solid))
        self.solid_render_action.setCheckable(True)

        self.line_render_action = QtWidgets.QAction(Node.RenderMode.Wireframe.value, self)
        self.line_render_action.setStatusTip('Render sample as wireframe object')
        self.line_render_action.setIcon(QtGui.QIcon(path_for('wireframe.png')))
        self.line_render_action.triggered.connect(lambda: self.scenes.changeRenderMode(Node.RenderMode.Wireframe))
        self.line_render_action.setCheckable(True)

        self.blend_render_action = QtWidgets.QAction(Node.RenderMode.Transparent.value, self)
        self.blend_render_action.setStatusTip('Render sample as transparent object')
        self.blend_render_action.setIcon(QtGui.QIcon(path_for('blend.png')))
        self.blend_render_action.triggered.connect(lambda: self.scenes.changeRenderMode(Node.RenderMode.Transparent))
        self.blend_render_action.setCheckable(True)
        self.blend_render_action.setChecked(True)

        self.render_action_group = QtWidgets.QActionGroup(self)
        self.render_action_group.addAction(self.solid_render_action)
        self.render_action_group.addAction(self.line_render_action)
        self.render_action_group.addAction(self.blend_render_action)

        self.show_bounding_box_action = QtWidgets.QAction('Toggle Bounding Box', self)
        self.show_bounding_box_action.setStatusTip('Toggle sample bounding box')
        self.show_bounding_box_action.setIcon(QtGui.QIcon(path_for('boundingbox.png')))
        self.show_bounding_box_action.setCheckable(True)
        self.show_bounding_box_action.setChecked(self.gl_widget.show_bounding_box)
        self.show_bounding_box_action.toggled.connect(self.gl_widget.showBoundingBox)

        self.show_coordinate_frame_action = QtWidgets.QAction('Toggle Coordinate Frame', self)
        self.show_coordinate_frame_action.setStatusTip('Toggle scene coordinate frame')
        self.show_coordinate_frame_action.setIcon(QtGui.QIcon(path_for('hide_coordinate_frame.png')))
        self.show_coordinate_frame_action.setCheckable(True)
        self.show_coordinate_frame_action.setChecked(self.gl_widget.show_coordinate_frame)
        self.show_coordinate_frame_action.toggled.connect(self.gl_widget.showCoordinateFrame)

        self.show_fiducials_action = QtWidgets.QAction('Toggle Fiducial Points', self)
        self.show_fiducials_action.setStatusTip('Show or hide fiducial points')
        self.show_fiducials_action.setIcon(QtGui.QIcon(path_for('hide_fiducials.png')))
        self.show_fiducials_action.setCheckable(True)
        self.show_fiducials_action.setChecked(True)
        action = self.scenes.toggleVisibility
        self.show_fiducials_action.toggled.connect(lambda state, a=Attributes.Fiducials: action(a, state))

        self.show_measurement_action = QtWidgets.QAction('Toggle Measurement Points', self)
        self.show_measurement_action.setStatusTip('Show or hide measurement points')
        self.show_measurement_action.setIcon(QtGui.QIcon(path_for('hide_measurement.png')))
        self.show_measurement_action.setCheckable(True)
        self.show_measurement_action.setChecked(True)
        self.show_measurement_action.toggled.connect(lambda state, a=Attributes.Measurements: action(a, state))

        self.show_vectors_action = QtWidgets.QAction('Toggle Measurement Vectors', self)
        self.show_vectors_action.setStatusTip('Show or hide measurement vectors')
        self.show_vectors_action.setIcon(QtGui.QIcon(path_for('hide_vectors.png')))
        self.show_vectors_action.setCheckable(True)
        self.show_vectors_action.setChecked(True)
        self.show_vectors_action.toggled.connect(lambda state, a=Attributes.Vectors: action(a, state))

        self.reset_camera_action = QtWidgets.QAction('Reset View', self)
        self.reset_camera_action.setStatusTip('Reset camera view')
        self.reset_camera_action.triggered.connect(self.gl_widget.resetCamera)
        self.reset_camera_action.setShortcut(QtGui.QKeySequence('Ctrl+0'))

        self.sample_manager_action = QtWidgets.QAction('Samples', self)
        self.sample_manager_action.setStatusTip('Open sample manager')
        self.sample_manager_action.triggered.connect(self.docks.showSampleManager)
        self.sample_manager_action.setShortcut(QtGui.QKeySequence('Ctrl+Shift+A'))

        self.fiducial_manager_action = QtWidgets.QAction('Fiducial Points', self)
        self.fiducial_manager_action.setStatusTip('Open fiducial point manager')
        self.fiducial_manager_action.triggered.connect(lambda: self.docks.showPointManager(PointType.Fiducial))
        self.fiducial_manager_action.setShortcut(QtGui.QKeySequence('Ctrl+Shift+F'))

        self.measurement_manager_action = QtWidgets.QAction('Measurements Points', self)
        self.measurement_manager_action.setStatusTip('Open measurement point manager')
        self.measurement_manager_action.triggered.connect(lambda: self.docks.showPointManager(PointType.Measurement))
        self.measurement_manager_action.setShortcut(QtGui.QKeySequence('Ctrl+Shift+M'))

        self.vector_manager_action = QtWidgets.QAction('Measurements Vectors', self)
        self.vector_manager_action.setStatusTip('Open measurement vector manager')
        self.vector_manager_action.triggered.connect(self.docks.showVectorManager)
        self.vector_manager_action.setShortcut(QtGui.QKeySequence('Ctrl+Shift+V'))

        self.simulation_dialog_action = QtWidgets.QAction('Simulation Results', self)
        self.simulation_dialog_action.setStatusTip('Open simulation dialog')
        self.simulation_dialog_action.triggered.connect(self.docks.showSimulationResults)
        self.simulation_dialog_action.setShortcut(QtGui.QKeySequence('Ctrl+Shift+L'))

        # Insert Menu Actions
        self.import_sample_action = QtWidgets.QAction('File...', self)
        self.import_sample_action.setStatusTip('Import sample from 3D model file')
        self.import_sample_action.triggered.connect(self.presenter.importSample)

        self.import_fiducial_action = QtWidgets.QAction('File...', self)
        self.import_fiducial_action.setStatusTip('Import fiducial points from file')
        self.import_fiducial_action.triggered.connect(lambda: self.presenter.importPoints(PointType.Fiducial))

        self.keyin_fiducial_action = QtWidgets.QAction('Key-in', self)
        self.keyin_fiducial_action.setStatusTip('Input X,Y,Z values of a fiducial point')
        self.keyin_fiducial_action.triggered.connect(lambda: self.docks.showInsertPointDialog(PointType.Fiducial))

        self.import_measurement_action = QtWidgets.QAction('File...', self)
        self.import_measurement_action.setStatusTip('Import measurement points from file')
        self.import_measurement_action.triggered.connect(lambda: self.presenter.importPoints(PointType.Measurement))

        self.keyin_measurement_action = QtWidgets.QAction('Key-in', self)
        self.keyin_measurement_action.setStatusTip('Input X,Y,Z values of a measurement point')
        self.keyin_measurement_action.triggered.connect(lambda: self.docks.showInsertPointDialog(PointType.Measurement))

        self.pick_measurement_action = QtWidgets.QAction('Graphical Selection', self)
        self.pick_measurement_action.setStatusTip('Select measurement points on a cross-section of sample')
        self.pick_measurement_action.triggered.connect(self.docks.showPickPointDialog)

        self.import_measurement_vector_action = QtWidgets.QAction('File...', self)
        self.import_measurement_vector_action.setStatusTip('Import measurement vectors from file')
        self.import_measurement_vector_action.triggered.connect(self.presenter.importVectors)

        self.select_strain_component_action = QtWidgets.QAction('Select Strain Component', self)
        self.select_strain_component_action.setStatusTip('Specify measurement vector direction')
        self.select_strain_component_action.triggered.connect(self.docks.showInsertVectorDialog)

        self.align_via_pose_action = QtWidgets.QAction('6D Pose', self)
        self.align_via_pose_action.setStatusTip('Specify position and orientation of sample on instrument')
        self.align_via_pose_action.triggered.connect(self.docks.showAlignSample)

        self.align_via_matrix_action = QtWidgets.QAction('Transformation Matrix', self)
        self.align_via_matrix_action.triggered.connect(self.presenter.alignSampleWithMatrix)
        self.align_via_matrix_action.setStatusTip('Align sample on instrument with transformation matrix')

        self.align_via_fiducials_action = QtWidgets.QAction('Fiducials Points', self)
        self.align_via_fiducials_action.triggered.connect(self.presenter.alignSampleWithFiducialPoints)
        self.align_via_fiducials_action.setStatusTip('Align sample on instrument using measured fiducial points')

        self.run_simulation_action = QtWidgets.QAction('&Run Simulation', self)
        self.run_simulation_action.setStatusTip('Start new simulation')
        self.run_simulation_action.setShortcut('F5')
        self.run_simulation_action.setIcon(QtGui.QIcon(path_for('play.png')))
        self.run_simulation_action.triggered.connect(self.presenter.runSimulation)

        self.stop_simulation_action = QtWidgets.QAction('&Stop Simulation', self)
        self.stop_simulation_action.setStatusTip('Stop active simulation')
        self.stop_simulation_action.setShortcut('Shift+F5')
        self.stop_simulation_action.setIcon(QtGui.QIcon(path_for('stop.png')))
        self.stop_simulation_action.triggered.connect(self.presenter.stopSimulation)

        self.compute_path_length_action = QtWidgets.QAction('Calculate Path Length', self)
        self.compute_path_length_action.setStatusTip('Enable path length calculation in simulation')
        self.compute_path_length_action.setCheckable(True)
        self.compute_path_length_action.setChecked(False)

        self.check_limits_action = QtWidgets.QAction('Hardware Limits Check', self)
        self.check_limits_action.setStatusTip('Enable positioning system joint limit checks in simulation')
        self.check_limits_action.setCheckable(True)
        self.check_limits_action.setChecked(True)

        self.show_sim_graphics_action = QtWidgets.QAction('Show Graphically', self)
        self.show_sim_graphics_action.setStatusTip('Enable graphics rendering in simulation')
        self.show_sim_graphics_action.setCheckable(True)
        self.show_sim_graphics_action.setChecked(True)

        self.check_collision_action = QtWidgets.QAction('Collision Detection', self)
        self.check_collision_action.setStatusTip('Enable collision detection in simulation')
        self.check_collision_action.setCheckable(True)
        self.check_collision_action.setChecked(False)

        self.show_sim_options_action = QtWidgets.QAction('Simulation Options', self)
        self.show_sim_options_action.setStatusTip('Change simulation settings')
        self.show_sim_options_action.triggered.connect(lambda: self.showPreferences(settings.Group.Simulation))

        # Instrument Actions
        self.positioning_system_action = QtWidgets.QAction('Positioning System', self)
        self.positioning_system_action.setStatusTip('Change positioning system settings')
        self.positioning_system_action.triggered.connect(self.docks.showPositionerControl)

        self.jaw_action = QtWidgets.QAction('Incident Jaws', self)
        self.jaw_action.setStatusTip('Change incident jaws settings')
        self.jaw_action.triggered.connect(self.docks.showJawControl)

        # Help Actions
        self.show_documentation_action = QtWidgets.QAction('&Documentation', self)
        self.show_documentation_action.setStatusTip('Show online documentation')
        self.show_documentation_action.setShortcut('F1')
        self.show_documentation_action.setIcon(QtGui.QIcon(path_for('question.png')))
        self.show_documentation_action.triggered.connect(self.showDocumentation)

        self.check_update_action = QtWidgets.QAction(f'&Check for Update', self)
        self.check_update_action.setStatusTip('Check the internet for software updates')
        self.check_update_action.triggered.connect(lambda: self.updater.check())

        self.show_about_action = QtWidgets.QAction(f'&About {MAIN_WINDOW_TITLE}', self)
        self.show_about_action.setStatusTip(f'About {MAIN_WINDOW_TITLE}')
        self.show_about_action.triggered.connect(self.about_dialog.show)

        # ToolBar Actions
        self.rotate_sample_action = QtWidgets.QAction('Rotate Sample', self)
        self.rotate_sample_action.setStatusTip('Rotate sample around fixed coordinate frame axis')
        self.rotate_sample_action.setIcon(QtGui.QIcon(path_for('rotate.png')))
        self.rotate_sample_action.triggered.connect(lambda: self.docks.showTransformDialog(TransformType.Rotate))

        self.translate_sample_action = QtWidgets.QAction('Translate Sample', self)
        self.translate_sample_action.setStatusTip('Translate sample along fixed coordinate frame axis')
        self.translate_sample_action.setIcon(QtGui.QIcon(path_for('translate.png')))
        self.translate_sample_action.triggered.connect(lambda: self.docks.showTransformDialog(TransformType.Translate))

        self.transform_sample_action = QtWidgets.QAction('Transform Sample with Matrix', self)
        self.transform_sample_action.setStatusTip('Transform sample with transformation matrix')
        self.transform_sample_action.setIcon(QtGui.QIcon(path_for('transform-matrix.png')))
        self.transform_sample_action.triggered.connect(lambda: self.docks.showTransformDialog(TransformType.Custom))

        self.move_origin_action = QtWidgets.QAction('Move Origin to Sample', self)
        self.move_origin_action.setStatusTip('Translate sample using bounding box')
        self.move_origin_action.setIcon(QtGui.QIcon(path_for('origin.png')))
        self.move_origin_action.triggered.connect(lambda: self.docks.showTransformDialog(TransformType.Origin))

        self.plane_align_action = QtWidgets.QAction('Rotate Sample by Plane Alignment', self)
        self.plane_align_action.setStatusTip('Rotate sample using a selected plane')
        self.plane_align_action.setIcon(QtGui.QIcon(path_for('plane_align.png')))
        self.plane_align_action.triggered.connect(lambda: self.docks.showTransformDialog(TransformType.Plane))

        self.toggle_scene_action = QtWidgets.QAction('Toggle Scene', self)
        self.toggle_scene_action.setStatusTip('Toggle between sample and instrument scene')
        self.toggle_scene_action.setIcon(QtGui.QIcon(path_for('exchange.png')))
        self.toggle_scene_action.triggered.connect(self.scenes.toggleScene)
        self.toggle_scene_action.setShortcut(QtGui.QKeySequence('Ctrl+T'))

    def createMenus(self):
        main_menu = self.menuBar()
        main_menu.setContextMenuPolicy(QtCore.Qt.PreventContextMenu)

        file_menu = main_menu.addMenu('&File')
        file_menu.addAction(self.new_project_action)
        file_menu.addAction(self.open_project_action)
        self.recent_menu = file_menu.addMenu('Open &Recent')
        file_menu.addAction(self.save_project_action)
        file_menu.addAction(self.save_as_action)
        file_menu.addSeparator()
        self.export_menu = file_menu.addMenu('Export...')
        self.export_menu.addAction(self.export_script_action)
        self.export_menu.addSeparator()
        self.export_menu.addAction(self.export_samples_action)
        self.export_menu.addAction(self.export_fiducials_action)
        self.export_menu.addAction(self.export_measurements_action)
        self.export_menu.addAction(self.export_vectors_action)
        self.export_menu.addAction(self.export_alignment_action)
        file_menu.addSeparator()
        file_menu.addAction(self.exit_action)
        file_menu.aboutToShow.connect(self.populateRecentMenu)

        edit_menu = main_menu.addMenu('&Edit')
        edit_menu.addAction(self.undo_action)
        edit_menu.addAction(self.redo_action)
        edit_menu.addAction(self.undo_view_action)
        edit_menu.addSeparator()
        edit_menu.addAction(self.preferences_action)

        view_menu = main_menu.addMenu('&View')
        view_menu.addAction(self.solid_render_action)
        view_menu.addAction(self.line_render_action)
        view_menu.addAction(self.blend_render_action)
        view_menu.addSeparator()
        self.view_from_menu = view_menu.addMenu('View From')
        for index, direction in enumerate(Directions):
            view_from_action = QtWidgets.QAction(direction.value, self)
            view_from_action.setStatusTip(f'View scene from the {direction.value} axis')
            view_from_action.setShortcut(QtGui.QKeySequence(f'Ctrl+{index+1}'))
            action = self.gl_widget.viewFrom
            view_from_action.triggered.connect(lambda ignore, d=direction: action(d))
            self.view_from_menu.addAction(view_from_action)

        view_menu.addAction(self.reset_camera_action)
        view_menu.addSeparator()
        view_menu.addAction(self.show_bounding_box_action)
        view_menu.addAction(self.show_fiducials_action)
        view_menu.addAction(self.show_measurement_action)
        view_menu.addAction(self.show_vectors_action)
        view_menu.addAction(self.show_coordinate_frame_action)
        view_menu.addSeparator()
        self.other_windows_menu = view_menu.addMenu('Other Windows')
        self.other_windows_menu.addAction(self.sample_manager_action)
        self.other_windows_menu.addAction(self.fiducial_manager_action)
        self.other_windows_menu.addAction(self.measurement_manager_action)
        self.other_windows_menu.addAction(self.vector_manager_action)
        self.other_windows_menu.addAction(self.simulation_dialog_action)

        insert_menu = main_menu.addMenu('&Insert')
        sample_menu = insert_menu.addMenu('Sample')
        sample_menu.addAction(self.import_sample_action)
        self.primitives_menu = sample_menu.addMenu('Primitives')

        for primitive in Primitives:
            add_primitive_action = QtWidgets.QAction(primitive.value, self)
            add_primitive_action.setStatusTip(f'Add {primitive.value} model as sample')
            add_primitive_action.triggered.connect(lambda ignore, p=primitive: self.docks.showInsertPrimitiveDialog(p))
            self.primitives_menu.addAction(add_primitive_action)

        fiducial_points_menu = insert_menu.addMenu('Fiducial Points')
        fiducial_points_menu.addAction(self.import_fiducial_action)
        fiducial_points_menu.addAction(self.keyin_fiducial_action)

        measurement_points_menu = insert_menu.addMenu('Measurement Points')
        measurement_points_menu.addAction(self.import_measurement_action)
        measurement_points_menu.addAction(self.keyin_measurement_action)
        measurement_points_menu.addAction(self.pick_measurement_action)

        measurement_vectors_menu = insert_menu.addMenu('Measurement Vectors')
        measurement_vectors_menu.addAction(self.import_measurement_vector_action)
        measurement_vectors_menu.addAction(self.select_strain_component_action)

        self.instrument_menu = main_menu.addMenu('I&nstrument')
        self.change_instrument_menu = self.instrument_menu.addMenu('Change Instrument')
        self.updateChangeInstrumentMenu()

        self.align_sample_menu = self.instrument_menu.addMenu('Align Sample on Instrument')
        self.align_sample_menu.addAction(self.align_via_pose_action)
        self.align_sample_menu.addAction(self.align_via_matrix_action)
        self.align_sample_menu.addAction(self.align_via_fiducials_action)
        self.collimator_action_groups = {}

        simulation_menu = main_menu.addMenu('&Simulation')
        simulation_menu.addAction(self.run_simulation_action)
        simulation_menu.addAction(self.stop_simulation_action)
        simulation_menu.addSeparator()
        simulation_menu.addAction(self.check_limits_action)
        simulation_menu.addAction(self.show_sim_graphics_action)
        simulation_menu.addAction(self.compute_path_length_action)
        simulation_menu.addAction(self.check_collision_action)
        simulation_menu.addSeparator()
        simulation_menu.addAction(self.show_sim_options_action)

        help_menu = main_menu.addMenu('&Help')
        help_menu.addAction(self.show_documentation_action)
        help_menu.addSeparator()
        help_menu.addAction(self.check_update_action)
        help_menu.addAction(self.show_about_action)

    def updateMenus(self):
        enable = False if self.presenter.model.project_data is None else True

        self.save_project_action.setEnabled(enable)
        self.save_as_action.setEnabled(enable)
        for action in self.export_menu.actions():
            action.setEnabled(enable)

        self.render_action_group.setEnabled(enable)

        for action in self.view_from_menu.actions():
            action.setEnabled(enable)
        self.reset_camera_action.setEnabled(enable)
        self.show_bounding_box_action.setEnabled(enable)
        self.show_coordinate_frame_action.setEnabled(enable)
        self.show_fiducials_action.setEnabled(enable)
        self.show_measurement_action.setEnabled(enable)
        self.show_vectors_action.setEnabled(enable)

        for action in self.other_windows_menu.actions():
            action.setEnabled(enable)

        self.import_sample_action.setEnabled(enable)
        for action in self.primitives_menu.actions():
            action.setEnabled(enable)

        self.import_fiducial_action.setEnabled(enable)
        self.keyin_fiducial_action.setEnabled(enable)

        self.import_measurement_action.setEnabled(enable)
        self.keyin_measurement_action.setEnabled(enable)
        self.pick_measurement_action.setEnabled(enable)

        self.import_measurement_vector_action.setEnabled(enable)
        self.select_strain_component_action.setEnabled(enable)

        self.instrument_menu.setEnabled(enable)

        self.run_simulation_action.setEnabled(enable)
        self.stop_simulation_action.setEnabled(enable)
        self.check_limits_action.setEnabled(enable)
        self.show_sim_graphics_action.setEnabled(enable)
        self.compute_path_length_action.setEnabled(enable)
        self.check_collision_action.setEnabled(enable)

        self.rotate_sample_action.setEnabled(enable)
        self.translate_sample_action.setEnabled(enable)
        self.transform_sample_action.setEnabled(enable)
        self.move_origin_action.setEnabled(enable)
        self.plane_align_action.setEnabled(enable)
        self.toggle_scene_action.setEnabled(enable)

    def createToolBar(self):
        toolbar = self.addToolBar('ToolBar')
        toolbar.setContextMenuPolicy(QtCore.Qt.PreventContextMenu)
        toolbar.setMovable(False)

        toolbar.addAction(self.new_project_action)
        toolbar.addAction(self.open_project_action)
        toolbar.addAction(self.save_project_action)
        toolbar.addAction(self.undo_action)
        toolbar.addAction(self.redo_action)
        toolbar.addSeparator()
        toolbar.addAction(self.solid_render_action)
        toolbar.addAction(self.line_render_action)
        toolbar.addAction(self.blend_render_action)
        toolbar.addAction(self.show_bounding_box_action)

        sub_button = QtWidgets.QToolButton(self)
        sub_button.setIcon(QtGui.QIcon(path_for('eye-slash.png')))
        sub_button.setPopupMode(QtWidgets.QToolButton.InstantPopup)
        sub_button.setToolTip('Show/Hide Elements')
        sub_button.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly)
        sub_button.addAction(self.show_fiducials_action)
        sub_button.addAction(self.show_measurement_action)
        sub_button.addAction(self.show_vectors_action)
        sub_button.addAction(self.show_coordinate_frame_action)
        toolbar.addWidget(sub_button)

        sub_button = QtWidgets.QToolButton(self)
        sub_button.setIcon(QtGui.QIcon(path_for('camera.png')))
        sub_button.setPopupMode(QtWidgets.QToolButton.InstantPopup)
        sub_button.setToolTip('Preset Views')
        sub_button.setMenu(self.view_from_menu)
        toolbar.addWidget(sub_button)

        toolbar.addSeparator()
        toolbar.addAction(self.rotate_sample_action)
        toolbar.addAction(self.translate_sample_action)
        toolbar.addAction(self.transform_sample_action)
        toolbar.addAction(self.move_origin_action)
        toolbar.addAction(self.plane_align_action)
        toolbar.addSeparator()
        toolbar.addAction(self.toggle_scene_action)

    def createStatusBar(self):
        sb = StatusBar()
        self.setStatusBar(sb)
        self.instrument_label = QtWidgets.QLabel()
        self.instrument_label.setAlignment(QtCore.Qt.AlignCenter)
        self.instrument_label.setToolTip('Current Instrument')
        sb.addPermanentWidget(self.instrument_label, alignment=QtCore.Qt.AlignLeft)

        self.cursor_label = QtWidgets.QLabel()
        self.cursor_label.setAlignment(QtCore.Qt.AlignCenter)
        sb.addPermanentWidget(self.cursor_label)

    @property
    def selected_render_mode(self):
        return Node.RenderMode(self.render_action_group.checkedAction().text())

    def readSettings(self):
        """ Loads window geometry from INI file """
        self.restoreGeometry(settings.value(settings.Key.Geometry))
        self.recent_projects = settings.value(settings.Key.Recent_Projects)

    def populateRecentMenu(self):
        self.recent_menu.clear()
        if self.recent_projects:
            for project in self.recent_projects:
                recent_project_action = QtWidgets.QAction(project, self)
                recent_project_action.triggered.connect(lambda ignore, p=project: self.openProject(p))
                self.recent_menu.addAction(recent_project_action)
        else:
            recent_project_action = QtWidgets.QAction('None', self)
            self.recent_menu.addAction(recent_project_action)

    def closeEvent(self, event):
        if self.presenter.confirmSave():
            settings.system.setValue(settings.Key.Geometry.value, self.saveGeometry())
            if self.recent_projects:
                settings.system.setValue(settings.Key.Recent_Projects.value, self.recent_projects)
            event.accept()
        else:
            event.ignore()

    def resetInstrumentMenu(self):
        self.instrument_menu.clear()
        self.instrument_menu.addMenu(self.change_instrument_menu)
        self.instrument_menu.addSeparator()
        self.instrument_menu.addAction(self.jaw_action)
        self.instrument_menu.addAction(self.positioning_system_action)
        self.instrument_menu.addSeparator()
        self.instrument_menu.addMenu(self.align_sample_menu)
        self.collimator_action_groups = {}

    def updateChangeInstrumentMenu(self):
        self.change_instrument_menu.clear()
        self.change_instrument_action_group = QtWidgets.QActionGroup(self)
        self.project_file_instrument_action = QtWidgets.QAction('', self)
        self.change_instrument_action_group.addAction(self.project_file_instrument_action)
        self.change_instrument_menu.addAction(self.project_file_instrument_action)
        self.project_file_instrument_separator = self.change_instrument_menu.addSeparator()
        self.project_file_instrument_action.setCheckable(True)
        self.project_file_instrument_action.setVisible(False)
        self.project_file_instrument_separator.setVisible(False)
        for name in sorted(self.presenter.model.instruments.keys()):
            change_instrument_action = QtWidgets.QAction(name, self)
            change_instrument_action.setStatusTip(f'Change instrument to {name}')
            change_instrument_action.setCheckable(True)
            change_instrument_action.triggered.connect(lambda ignore, n=name: self.presenter.changeInstrument(n))
            self.change_instrument_action_group.addAction(change_instrument_action)
            self.change_instrument_menu.addAction(change_instrument_action)
        self.toggleActiveInstrument()

    def toggleActiveInstrument(self):
        model = self.presenter.model
        if model.project_data is None or model.instrument is None:
            return

        self.instrument_label.setText(model.instrument.name)
        if model.checkInstrumentVersion():
            toggleActionInGroup(model.instrument.name, self.change_instrument_action_group)
            self.project_file_instrument_action.setVisible(False)
            self.project_file_instrument_separator.setVisible(False)
        else:
            self.project_file_instrument_action.setText(f'{model.instrument.name} (Project)')
            self.project_file_instrument_action.setChecked(True)
            self.project_file_instrument_action.setVisible(True)
            self.project_file_instrument_separator.setVisible(True)

    def addCollimatorMenu(self, detector, collimators, active, menu='Detector', show_more_settings=False):
        collimator_menu = QtWidgets.QMenu(menu, self)
        self.instrument_menu.insertMenu(self.jaw_action, collimator_menu)
        action_group = QtWidgets.QActionGroup(self)
        for name in collimators:
            change_collimator_action = self.__createChangeCollimatorAction(name, active, detector)
            collimator_menu.addAction(change_collimator_action)
            action_group.addAction(change_collimator_action)

        change_collimator_action = self.__createChangeCollimatorAction('None', str(active), detector)
        collimator_menu.addAction(change_collimator_action)
        action_group.addAction(change_collimator_action)
        self.collimator_action_groups[detector] = action_group
        if show_more_settings:
            collimator_menu.addSeparator()
            other_settings_action = QtWidgets.QAction('Other Settings', self)
            other_settings_action.setStatusTip('Change detector position settings')
            other_settings_action.triggered.connect(lambda ignore, d=detector: self.docks.showDetectorControl(d))
            collimator_menu.addAction(other_settings_action)

    def __createChangeCollimatorAction(self, name, active, detector):
        change_collimator_action = QtWidgets.QAction(name, self)
        change_collimator_action.setStatusTip(f'Change collimator to {name}')
        change_collimator_action.setCheckable(True)
        change_collimator_action.setChecked(active == name)
        change_collimator_action.triggered.connect(lambda ignore,
                                                          n=detector,
                                                          t=name: self.presenter.changeCollimators(n, t))

        return change_collimator_action

    def showUndoHistory(self):
        """ shows Undo History"""
        self.undo_view = QtWidgets.QUndoView(self.undo_stack)
        self.undo_view.setWindowTitle('Undo History')
        self.undo_view.show()
        self.undo_view.setAttribute(QtCore.Qt.WA_QuitOnClose, False)

    def showNewProjectDialog(self):
        if self.presenter.confirmSave():
            self.project_dialog = ProjectDialog(self.recent_projects, parent=self)
            self.project_dialog.setModal(True)
            self.project_dialog.show()

    def showPreferences(self, group=None):
        self.preferences = Preferences(self)
        self.preferences.setActiveGroup(group)
        self.preferences.setModal(True)
        self.preferences.show()

    def showAlignmentError(self):
        self.alignment_error = AlignmentErrorDialog(parent=self)
        self.alignment_error.setModal(True)
        self.alignment_error.show()

    def showPathLength(self):
        simulation = self.presenter.model.simulation
        if simulation is None:
            return

        if not simulation.compute_path_length:
            self.showMessage('Path Length computation is not enabled for this simulation.\n'
                             'Go to "Simulation > Compute Path Length" to enable it then \nrestart simulation.',
                             MessageSeverity.Information)
            return

        self.path_length_plotter = PathLengthPlotter(self)
        self.path_length_plotter.setModal(True)
        self.path_length_plotter.show()

    def showSampleExport(self, sample_list):
        sample_export = SampleExportDialog(sample_list, parent=self)
        if sample_export.exec() != QtWidgets.QFileDialog.Accepted:
            return ''

        return sample_export.selected

    def showScriptExport(self):
        simulation = self.presenter.model.simulation
        if simulation is None:
            self.showMessage('There are no simulation results to write in script.', MessageSeverity.Information)
            return

        if simulation.isRunning():
            self.showMessage('Finish or Stop the current simulation before attempting to write script.',
                             MessageSeverity.Information)
            return

        if not simulation.results:
            self.showMessage('There are no simulation results to write in script.', MessageSeverity.Information)
            return

        script_export = ScriptExportDialog(simulation, parent=self)
        script_export.setModal(True)
        script_export.show()

    def showProjectName(self):
        project_name = self.presenter.model.project_data['name']
        save_path = self.presenter.model.save_path
        if save_path:
            title = f'{project_name} [{save_path}] - {MAIN_WINDOW_TITLE}'
        else:
            title = f'{project_name} - {MAIN_WINDOW_TITLE}'
        self.setWindowTitle(title)

    def showSaveDialog(self, filters, current_dir='', title=''):
        directory = current_dir if current_dir else os.path.splitext(self.presenter.model.save_path)[0]
        filename = FileDialog.getSaveFileName(self, title,  directory, filters)
        return filename

    def showOpenDialog(self, filters, current_dir='', title=''):
        directory = current_dir if current_dir else os.path.dirname(self.presenter.model.save_path)
        filename = FileDialog.getOpenFileName(self, title, directory, filters)
        return filename

    def showMessage(self, message, severity=MessageSeverity.Critical):
        """
        Shows an message with a given severity.

        :param message: Error message
        :type message: str
        :param severity: severity of the message
        :type severity: MessageSeverity
        """
        if severity == MessageSeverity.Critical:
            QtWidgets.QMessageBox.critical(self, MAIN_WINDOW_TITLE, message)
        elif severity == MessageSeverity.Warning:
            QtWidgets.QMessageBox.warning(self, MAIN_WINDOW_TITLE, message)
        else:
            QtWidgets.QMessageBox.information(self, MAIN_WINDOW_TITLE, message)

    def showSaveDiscardMessage(self, name):
        """
        Shows an message to confirm if unsaved changes should be saved.

        :param name: the name of the unsaved project
        """
        message = 'The document has been modified.\n\n' \
                  'Do you want to save changes to "{}"?\t'.format(name)
        buttons = QtWidgets.QMessageBox.Save | QtWidgets.QMessageBox.Discard | QtWidgets.QMessageBox.Cancel
        reply = QtWidgets.QMessageBox.warning(self,
                                              MAIN_WINDOW_TITLE,
                                              message, buttons,
                                              QtWidgets.QMessageBox.Cancel)

        if reply == QtWidgets.QMessageBox.Save:
            return MessageReplyType.Save
        if reply == QtWidgets.QMessageBox.Discard:
            return MessageReplyType.Discard
        else:
            return MessageReplyType.Cancel

    def showSelectChoiceMessage(self, message, choices, default_choice=0):
        message_box = QtWidgets.QMessageBox(self)
        message_box.setWindowTitle(MAIN_WINDOW_TITLE)
        message_box.setText(message)

        buttons = []
        for choice in choices:
            buttons.append(QtWidgets.QPushButton(choice))
            message_box.addButton(buttons[-1], QtWidgets.QMessageBox.YesRole)

        message_box.setDefaultButton(buttons[default_choice])
        message_box.exec()

        for index, button in enumerate(buttons):
            if message_box.clickedButton() == button:
                return choices[index]

    def openProject(self, filename=''):
        """
        This function loads a project with the given filename. if filename is empty,
        a file dialog will be opened.

        :param filename: full path of file
        :type filename: str
        """
        if not self.presenter.confirmSave():
            return

        if not filename:
            filename = self.showOpenDialog('hdf5 File (*.h5)', title='Open Project',
                                           current_dir=self.presenter.model.save_path)
            if not filename:
                return

        self.presenter.useWorker(self.presenter.openProject, [filename], self.presenter.updateView,
                                 self.presenter.projectOpenError)

    def showDocumentation(self):
        """
        This function opens the documentation html in the system's default browser
        """
        import webbrowser
        webbrowser.open_new(DOCS_URL)

    def showUpdateMessage(self, message):
        """ Shows software update message in a custom dialog with a check-box to change
        the "check update on startup" setting.

        :param message: message
        :type message: string
        """
        message_box = QtWidgets.QMessageBox(self)
        message_box.setWindowTitle(f'{MAIN_WINDOW_TITLE} Update')
        message_box.setText(message)
        message_box.setTextFormat(QtCore.Qt.RichText)
        checkbox = QtWidgets.QCheckBox('Check for updates on startup')
        checkbox.setChecked(settings.value(settings.Key.Check_Update))
        checkbox.stateChanged.connect(lambda state: settings.system.setValue(settings.Key.Check_Update.value,
                                                                             state == QtCore.Qt.Checked))
        message_box.setCheckBox(checkbox)

        cancel_button = QtWidgets.QPushButton('Close')
        message_box.addButton(cancel_button, QtWidgets.QMessageBox.NoRole)

        message_box.exec()

class Updater:

    def __init__(self, parent):
        self.startup = False
        self.parent = parent

    def check(self, startup=False):
        """ Asynchronously checks for new release using the Github release API and notifies the user when
        update is found, not found or an error occurred. When startup is true, the user will
        only be notified if update is found.

        :param startup: flag that indicates the check is at startup
        :type startup: bool
        """
        if startup and not settings.value(settings.Key.Check_Update):
            return

        self.startup = startup
        if not startup:
            self.parent.progress_dialog.show('Checking the Internet for Updates')
        self.parent.presenter.useWorker(self.checkHelper, [], self.onSuccess, self.onFaiure,
                                        self.parent.progress_dialog.close)

    def checkHelper(self):
        import json
        import urllib.request

        response = urllib.request.urlopen('https://api.github.com/repos/ISISNeutronMuon/SScanSS-2/releases/latest')
        tag_name = json.loads(response.read()).get('tag_name')
        if not tag_name or tag_name.endswith(__version__):
            return False, __version__

        return True, tag_name

    def onSuccess(self, result):
        update_found, tag_name = result
        if update_found:
            self.parent.showUpdateMessage(f'A new version {tag_name} of {MAIN_WINDOW_TITLE} is available. Download the '
                                        'installer from <a href="https://github.com/ISISNeutronMuon/SScanSS-2/releases">'
                                        'https://github.com/ISISNeutronMuon/SScanSS-2/releases</a>.<br/><br/>')
        else:
            if self.startup:
                return
            self.showUpdateMessage(f'You are running the latest version of {MAIN_WINDOW_TITLE}.<br/><br/>')

    def onFaiure(self, exception):
        from urllib.error import URLError, HTTPError
        import logging

        logging.error('An error occurred while checking for updates', exc_info=exception)
        if self.startup:
            return

        if isinstance(exception,  HTTPError):
            self.parent.showUpdateMessage(f'You are running the latest version of {MAIN_WINDOW_TITLE}.<br/><br/>')
        elif isinstance(exception, URLError):
            self.parent.showMessage('An error occurred when attempting to connect to update server. '
                                    'Check your internet connection and/or firewall and try again.')


# -*- coding: utf-8 -*-
"""
Created on Wed Jun 13 21:47:09 2018
baidu
@author: mhy
"""

import requests
import re
import json
import time
import random
import math

#百度坐标拾取器获得 北京城区

#lat1=39.820735
#lng1=116.216091
#
#lat2=40.024808
#lng2=116.548392

#淮南市城区
lat1=32.573204
lng1=116.804016

lat2=32.722048
lng2=116.986264

all_shop_id=[]

headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36',
}

#批量生成坐标
def genPositon(lat1,lng1,lat2,lng2,step=1):
    #step单位是km，1经度度约等于111km
    step_lng = step / (111.0)
    step_lat = step / (111.0) * math.cos(math.radians(lat1))

    pos_list = []

    cur_lon = lng1 + step_lng / 2
    while (cur_lon < lng2):
        cur_lat = lat1 + step_lat / 2
        while (cur_lat < lat2):
            print([cur_lat, cur_lon])
            pos_list.append([cur_lat, cur_lon])
            cur_lat = cur_lat + step_lat

        cur_lon = cur_lon + step_lng
    return pos_list

def coords_transfer(lng,lat):
    coords=str(lng)+','+str(lat)

    #坐标转换API
    url='http://api.map.baidu.com/geoconv/v1/?coords='+coords+'&from=5&to=6&ak=X3jQGUexW0e6SpgEuGOEBPByeDA2ttm3'
    coords_req=requests.get(url=url,headers=headers)

    xy=coords_req.text

    json_dict=json.loads(xy)
    lng = json_dict['result'][0]['x']
    lat = json_dict['result'][0]['y']
    return lng,lat

def getURL(lng,lat):
    url='http://waimai.baidu.com/waimai'
    data={
    'qt': 'shoplist',
    'lat': lat,
    'lng': lng,
    }

    req=requests.get(url=url,params=data,headers=headers,allow_redirects=False)
    #发生重定向
    new_url=''
    if req.status_code==302:
        location=req.headers['Location']
        new_url='http://waimai.baidu.com'+location
    return new_url

fjw=open('shop_jw_huainan.txt','w')
#获取当前搜索中心所有商家信息
def count_shops(new_url):
    count=0
    allshops=[]
    shops=[]
    num=1

    while( (len(shops)!=0) or (num==1)):
        time.sleep(0.2+random.random())
        cur_url = new_url + '?display=json&page='+str(num)+'&count=40'
        print('URL: ' + cur_url)
        try:
            req=requests.get(url=cur_url,headers=headers,timeout=3)
            shops=re.findall('"shop_id":"[0-9]+"',req.text,re.S)
            latlngs=re.findall('"shop_lng":[0-9]+,"shop_lat":[0-9]+',req.text,re.S)
        except:
            print('wrong')

        k=0
        for shop in shops:
            sid=shop.split(':')[1]
            sid=sid[1:len(sid)-1]

            if sid not in allshops:
                allshops.append(sid)
            #如果不在所有商家列表中
            if sid not in all_shop_id:
                all_shop_id.append(sid)
                s=sid+'\t'+latlngs[k]+'\n'

                print('!!!! new SHOP ID '+s)
                fjw.write(s)
            k=k+1

        num=num+1
    count=len(allshops) #该经纬度商家计数
    return count

fout=open('format_count_huainan.txt','w')
coords=genPositon(lat1,lng1,lat2,lng2,2)
print('\ntotal coord is'+ str(len(coords)))
kk=1
for (lat,lng) in coords:
    print('\n\n-----current latitude and longitude is')
    print(lat)
    print(lng)
    print('Number '+str(kk))
    lng1,lat1=coords_transfer(lng,lat)
    new_url = getURL(lng1,lat1)
    count=count_shops(new_url)
    print(count)
    s='{"lng":'+str(lng)+',"lat":'+str(lat)+',"count":'+str(count)+'},'
    print('\n'+s)
    fout.write(s)
    kk=kk+1

fout.close()
fjw.close()


import gym
import math
import os
import pickle
import neat
import numpy as np
import nes
from neat.reporting import *
import logging

class OpenAITask:
    runs_per_net = 1
    test_repeat = 10
    success_threshold = None
    n_cpus = 8

    def __init__(self):
        self.env = self.get_env()

    def play(self, net, render=False, test=True):
        state = self.scale_state(self.env.reset())
        fitness = 0.0
        for step in range(self.step_limit):
            if render:
                self.env.render()
            action = self.get_action(net.activate(state))
            state, reward, done, info = self.env.step(action)
            state = self.scale_state(state)
            fitness += self.get_fitness(reward)
            if done:
                break
        if test:
            fitnesses = np.zeros(self.test_repeat)
            for i in range(self.test_repeat):
                fitnesses[i] = self.play(net, False, False)
            mean_fitness = np.mean(fitnesses)
            if mean_fitness >= self.success_threshold:
                return mean_fitness
            else:
                if fitness >= self.success_threshold:
                    return self.success_threshold - 1
                else:
                    return fitness
        else:
            return fitness

class CartPole(OpenAITask):
    gym_name = 'CartPole-v0'
    tag = 'cartpole'
    step_limit = 600
    angle_limit_radians = 15 * math.pi / 180
    position_limit = 2.4

    def __init__(self):
        OpenAITask.__init__(self)

    def scale_state(self, state):
        return [0.5 * (state[0] + self.position_limit) / self.position_limit,
                (state[1] + 0.75) / 1.5,
                0.5 * (state[2] + self.angle_limit_radians) / self.angle_limit_radians,
                (state[3] + 1.0) / 2.0]

    def get_action(self, value):
        return 1 if value[0] > 0.5 else 0

    def get_fitness(self, reward):
        return reward

    def get_env(self):
        return gym.make(self.gym_name)

class MountainCar(OpenAITask):
    gym_name = 'MountainCar-v0'
    tag = 'mountain-car'
    step_limit = 250
    test_repeat = 10
    success_threshold = -110

    def __init__(self):
        OpenAITask.__init__(self)

    def scale_state(self, state):
        return [(state[0] + 1.2) / 1.8,
                (state[1] + 0.07) / 0.14]

    def get_action(self, value):
        return np.argmax(value)

    def get_fitness(self, reward):
        return reward

    def get_env(self):
        env = gym.make(self.gym_name)
        env._max_episode_steps = self.step_limit
        return env

class SuperMario:
    runs_per_net = 1
    n_cpus = 1
    step_limit = 100000
    tag = 'super-mario'
    goal = 3266

    def __init__(self):
        self.client = nes.Client()
        self.actions = [self.client.msg_press_right,
                        self.client.msg_press_left,
                        self.client.msg_press_up,
                        self.client.msg_press_down,
                        self.client.msg_press_A]

    def reset(self):
        self.client.reset()
        return self.client.info()

    def step(self, action):
        self.client.send(self.actions[action])
        info = self.client.info()
        info['dead'] = info['state'] == 11
        info['x'] = info['mario']['x']
        return info

    def get_action(self, values):
        return np.argmax(values)

    def scale_state(self, state):
        return state + [1.0]

    def play(self, net, render=True):
        max_x = -1
        step_counter = 0
        info = self.reset()
        state = self.scale_state(info['tiles'])
        for step in range(self.step_limit):
            step_counter += 1
            values = net.activate(state)
            action = self.get_action(values)
            info = self.step(action)
            if info['x'] > max_x:
                max_x = info['x']
                step_counter = 0
            if step_counter > 20:
                break
            if max_x >= self.goal:
                break
            if info['dead']:
                break
            state = self.scale_state(info['tiles'])
        return max_x

# task = CartPole()
task = MountainCar()
# task = SuperMario()

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
fh = logging.FileHandler('log/%s.txt' % task.tag)
fh.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
ch.setFormatter(formatter)
logger.addHandler(fh)
logger.addHandler(ch)

def eval_genome(genome, config):
    net = neat.nn.FeedForwardNetwork.create(genome, config)
    fitnesses = []
    for runs in range(task.runs_per_net):
        fitness = task.play(net)
        fitnesses.append(fitness)
    return min(fitnesses)

def eval_genomes(genomes, config):
    for genome_id, genome in genomes:
        genome.fitness = eval_genome(genome, config)

class CustomReporter(BaseReporter):
    def found_solution(self, config, generation, best):
        self.generation = generation

def evolve(config, pop_size, step_limit):
    config.pop_size = pop_size
    task.step_limit = step_limit

    pop = neat.Population(config)
    stats = neat.StatisticsReporter()
    pop.add_reporter(stats)
    pop.add_reporter(neat.StdOutReporter(True))
    reporter = CustomReporter()
    pop.add_reporter(reporter)

    pe = neat.ParallelEvaluator(task.n_cpus, eval_genome)
    winner = pop.run(pe.evaluate)

    return winner, reporter.generation

def run():
    local_dir = os.path.dirname(__file__)
    config_path = os.path.join(local_dir, 'config-%s.txt' % task.tag)
    config = neat.Config(neat.DefaultGenome, neat.DefaultReproduction,
                         neat.DefaultSpeciesSet, neat.DefaultStagnation,
                         config_path)

    pop_sizes = [250, 200, 150]
    step_limits = [250, 200, 150]
    runs = 30
    results = dict()
    for pop_size in pop_sizes:
        for step_limit in step_limits:
            success_generation = np.zeros(runs)
            for r in range(runs):
                logger.debug('pop size: %d, step limit: %d, run: %d' % (pop_size, step_limit, r))
                winner, success_generation[r] = evolve(config, pop_size, step_limit)
            results[(pop_size, step_limit)] = (success_generation, winner)
            with open('statistics-%s.bin' % task.tag, 'wb') as f:
                pickle.dump(results, f)

    # winner = evolve(config, 250, 250)

    with open('winner-%s.bin' % task.tag, 'wb') as f:
        pickle.dump(winner, f)

    # print(winner)

def show():
    local_dir = os.path.dirname(__file__)
    config_path = os.path.join(local_dir, 'config-%s.txt' % task.tag)
    config = neat.Config(neat.DefaultGenome, neat.DefaultReproduction,
                         neat.DefaultSpeciesSet, neat.DefaultStagnation,
                         config_path)

    with open('statistics-%s.bin' % task.tag, 'rb') as f:
        results = pickle.load(f)
    # print results

    # winner = results[(250, 250)][1]
    # with open('winner-%s.bin' % task.tag, 'rb') as f:
    #     winner = pickle.load(f)
    # print(winner)
    # net = neat.nn.FeedForwardNetwork.create(winner, config)
    # print task.play(net, True)

if __name__ == '__main__':
    # show()
    run()


import linecache
import traceback
import resource
import filecmp
from sklearn.utils import shuffle
import tensorflow as tf
import subprocess
import json
import seaborn as sns
import matplotlib.pyplot as plt
import re
import hashlib
import numpy as np
import os,sys
import pickle
import gensim.models as w2v
import pandas as pd
import nltk
import generateFeatures as feat
from bert_serving.server.helper import get_args_parser
from bert_serving.server.helper import get_shutdown_parser
from bert_serving.server import BertServer
from bert_serving.client import BertClient
tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.FATAL)

filename = sys.argv[0]
cwd = os.path.abspath(filename+"/..")

modelpath = cwd+"/w2vModel"
data_dir = cwd+"/data"
dataset_dir = data_dir+"/datasets"
bert_dir = cwd+"/res/bert"
hash_path = cwd+"/data/hash.txt"
spec_dir = cwd+"/res/specificity/Domain-Agnostic-Sentence-Specificity-Prediction"

#max num of words in a sentence
#only used for w2v
MAX_SENT_LEN = 2000
MIN_BODY_LEN = 50
EMB_DIM_SIZE = 300
#EMB_DIM_SIZE = 100

stages = ["concat","data","folds","bert","features","complexity","specificity","w2v"]

def clean_text(string):
    """
    Tokenization/string cleaning for all datasets except for SST.
    Original taken from https://github.com/yoonkim/CNN_sentence/blob/master/process_data.py
    """
    string = re.sub(r"[^A-Za-z0-9(),!?\'\`]", " ", string)
    string = re.sub(r"\'s", " \'s", string)
    string = re.sub(r"\'ve", " \'ve", string)
    string = re.sub(r"n\'t", " n\'t", string)
    string = re.sub(r"\'re", " \'re", string)
    string = re.sub(r"\'d", " \'d", string)
    string = re.sub(r"\'ll", " \'ll", string)
    string = re.sub(r",", " , ", string)
    string = re.sub(r"!", " ! ", string)
    string = re.sub(r"\(", " \( ", string)
    string = re.sub(r"\)", " \) ", string)
    string = re.sub(r"\?", " \? ", string)
    string = re.sub(r"\s{2,}", " ", string)
    return string.strip()

def pos(sentence):
    tokens = nltk.word_tokenize(sentence)
    tagsAndTokes = nltk.pos_tag(tokens)
    justTags = " ".join([e[1] for e in tagsAndTokes])
    return justTags

class LineSeekableFile:
    def __init__(self, seekable):
        self.c = 0
        self.fin = seekable
        self.line_map = list() # Map from line index -> file position.
        self.line_map.append(0)
        while seekable.readline():
            print("Creating LineSeekableFile Object: ",self.c)
            self.c += 1
            self.line_map.append(seekable.tell())

    def __getitem__(self, index):
        # NOTE: This assumes that you're not reading the file sequentially.
        # For that, just use 'for line in file'.
        self.fin.seek(self.line_map[index])
        return self.fin.readline()

def save_p(filename, data):
    with open(filename, "wb") as p:
        pickle.dump(data, p, protocol=4)

def read_p(filename):
    with open(filename, "rb") as f:
        return pickle.load(f)

#true if data is the same, False if not
def check_hash(df_hash, num_folds, drop_feat_idx=None, stage="data"):
    print(stage.upper(), " CHECK> Checking Hash Path on: ",hash_path)
    if os.path.exists(hash_path):
        with open(hash_path, "r") as h:
            lines = h.readlines()
            old_folds = lines[1].split(" ")[1][:-1]
            old_feat_idx = lines[-2].split("drop_feat: ")[1][:-1]
            print("old_feat_idx:", old_feat_idx)
            for i,l in enumerate(lines):
                if l.startswith(stage):
                    old_hash = l.split(" ")[1][:-1]

            print("Old and New Hash: ",old_hash[:5],df_hash[:5]," Same? ", (old_hash == df_hash))
            print("Old and New #folds:",old_folds, num_folds, " Same? ", (int(old_folds)==num_folds))
            print("Old and New Drop_Feat: ",old_feat_idx,drop_feat_idx," Same? ", (old_feat_idx == str(drop_feat_idx)),"\n")

        if old_hash != df_hash:
            return False
        if stage in ["drop_feat", "data"] and (old_feat_idx != str(drop_feat_idx)):
            return False
        if stage == "data" and (int(old_folds) != num_folds):
            return False
        return True
    return False

def savehash(stage, hashcode, drop_feat_idx=None):
    with open(hash_path, "r") as h:
        data = h.readlines()
        for i,l in enumerate(data):
            if l.startswith(stage):
                if stage == "drop_feat":
                    data[i] = stage+": "+str(drop_feat_idx)+"\n"
                else:
                    data[i] = stage+": "+hashcode+"\n"
    with open(hash_path, "w") as h:
        h.writelines(data)

def reset_hash(force_reload):
    if force_reload == "all" :
        for s in stages:
            savehash(s,"0")
    if force_reload == "emb" :
        for s in ["data", "bert", "concat"]:
            savehash(s,"0")
    if force_reload == "feat" :
        for s in ["data", "features", "concat", "complexity", "specificity"]:
            savehash(s,"0")
    if force_reload == "just_reload" :
        for s in ["data", "concat"]:
            savehash(s,"0")

#run concat+normalize.py inside dataset/ before loading data
def load_data(emb_type='w2v', collapse_classes=False, fold_test=None, num_folds=1, random_state=None, force_reload=None, drop_feat_idx=[], only_claims=False, feature_list=["inf","div","qua","aff","sbj","spe","pau","unc","pas"]):
    print('Loading data from',dataset_dir)
    data = pd.read_csv(dataset_dir+"/dataset.csv", sep=',')

    if force_reload is not None: reset_hash(force_reload)

    print("size of initial \"dataset\":",len(data))
    #determines if data will be whole body or only claims
    #df = df[lens < MAX_SENT_LEN]
    if only_claims:
        df = data[['claim','verdict']].copy()
        df = df.rename(columns={"claim": "body"})
        df = df[df['body'].map(len) > MIN_BODY_LEN]
        print("after dropping origins with less than "+str(MIN_BODY_LEN)+" chars:",len(df))
    else:
        df = data[['o_body','verdict']].copy()
        df = df.rename(columns={"o_body": "body"})
    if 'o_url' in df.columns:
        df = df.drop_duplicates(subset='o_url', keep='first')
    print("after dropping duplicates:",len(df))
    df.body = df.body.astype('str')
    df.verdict = df.verdict.astype('str')
    df['verdict'] = df['verdict'].str.lower()
    df.body.apply(clean_text)
    df = df.reset_index()

    if(collapse_classes):
        print("labels before collapse classes:", df.verdict.unique())
        df.loc[df['verdict'] == "mfalse", 'verdict'] = 'false'
        df.loc[df['verdict'] == "false.", 'verdict'] = 'false'
        df.loc[df['verdict'] == "mtrue", 'verdict'] = 'true'
        df.loc[df['verdict'] == "true.", 'verdict'] = 'true'

    labels = ['true', 'false']
    print(df['verdict'].value_counts())
    df = df.loc[df.verdict.isin(labels)]
    print("considered labels:", df.verdict.unique())
    print("after dropping invalid labels:",len(df))
    df.to_csv(data_dir+'/data.csv', sep="\t", index=False)

    #creating hash
    json_data = df.to_json().encode()
    df = df.sample(frac=1, random_state=random_state)
    df_hash = hashlib.sha256(json_data).hexdigest()

    labels_idx = [labels.index(label) for label in labels]
    labels_one_hot = np.eye(len(labels))[labels_idx]
    label_to_oh = {label:labels_one_hot[labels.index(label)] for label in labels}

    print("MEMORY: ",resource.getrusage(resource.RUSAGE_SELF).ru_maxrss)

    assert (num_folds > 2), "Needs at least three folds for Train/Dev/Test to be different from each other"
    #determine train_fold and dev_fold:
    bucket_size = int(len(data.index)/num_folds)
    fold_dev = 0 if fold_test == num_folds-1 else fold_test+1

    if not check_hash(df_hash, num_folds, drop_feat_idx=drop_feat_idx):
        lens = np.asarray([len(e.split(" ")) for e in df['body'].values])
        #IS THIS LINE NEEDED?
        #df.reset_index(drop = True, inplace = True)
        num_entries = len(df)

        #plots the data distribution by number of words
        print("Number of entries: ", num_entries)
        print("True/False: ",df.groupby('verdict').count())
        print("Mean and Std of number of words per document: ",np.mean(lens),np.std(lens), "\n")
        #input("Press any key to continue.")

        ###################################
        ############# FEATURES ############
        ###################################
        #check if new linguistic features should be generated
        flag_concat = False
        if not check_hash(df_hash, num_folds, stage="complexity") and "inf" in feature_list:
            flag_concat = True
            #Generate the features ndarray and save it to a pickle
            try:
                feat.generate_complexity()
            except Exception as e:
                print(traceback.format_exc())
                input("Error occured while GENERATING COMPLEXITY. Press any key to exit.")
                sys.exit(1)
            savehash("complexity", hashcode=df_hash)
        if not check_hash(df_hash, num_folds, stage="specificity") and "spe" in feature_list:
            flag_concat = True
            try:
                feat.generate_specificity()
            except Exception as e:
                print(traceback.format_exc())
                input("Error occured while GENERATING SPECIFICITY. Press any key to exit.")
                sys.exit(1)
            savehash("specificity", hashcode=df_hash)

        if not check_hash(df_hash, num_folds, drop_feat_idx=drop_feat_idx, stage="features") or (force_reload == 'just_reload'):
            flag_concat = True
            try:
                bool_reload = True if force_reload == "just_reload" else False
                features = feat.generateFeats(feature_list, just_reload = bool_reload)
                print(features)
                input()

            except Exception as e:
                print(traceback.format_exc())
                input("Error occured while GENERATING FEATURES. Press any key to exit.")
                sys.exit(1)
            save_p(data_dir+"/features", features)
            print("Generated Features. Saved to pickle.")
            savehash("features", hashcode=df_hash, drop_feat_idx=drop_feat_idx)

        #check if drop_features is NOT the same
        if not check_hash(df_hash, num_folds, drop_feat_idx=drop_feat_idx, stage="drop_feat"):
            flag_concat = True
            savehash("drop_feat", hashcode=df_hash, drop_feat_idx=drop_feat_idx)

        print("MEMORY AFTER FEATURES: ",resource.getrusage(resource.RUSAGE_SELF).ru_maxrss)

        ####################################
        ############### BERT ###############
        ####################################
        #check if new bert should be generated
        if not check_hash(df_hash, num_folds, stage="bert"):
            try:
                #creates the shuffle order (not random)
                index_shuf = list(range(len(df)))

                #creates a list of N=folds lists, each inner list contains the index of the elements of each fold
                bert_folds = np.array_split(index_shuf, num_folds)
                bert_folds = [a.tolist() for a in bert_folds]

                #creates an ordered list of N=entries of integers(:folds) indicating the fold idx of each entry
                fold_idx = [bert_folds.index(list(sl)) for e in index_shuf for sl in bert_folds if e in list(sl)]

                #start the bert-as-a-service server
                bert_dir = os.environ.get("BERT_BASE_DIR")
                #args = get_args_parser().parse_args(['-model_dir', bert_dir, '-port', '5555', '-port_out', '5556', '-max_seq_len', '512', '-mask_cls_sep'])
                #server = BertServer(args)
                #server.start()

                #delete the bert.csv files inside the folds
                for i in range(num_folds):
                    filename = data_dir+"/folds/"+str(i)+"/bert.csv"
                    if os.path.exists(filename):
                        subprocess.call("rm -rf "+filename, shell=True, cwd=data_dir)

                #TODO make this process read only one fold at a time
                for fold, idx in zip(fold_idx, index_shuf):
                    #generates the encodings for the texts
                    bc = BertClient(check_version=False)
                    b = bc.encode([df.body[idx]])[0]

                    bert_df = pd.DataFrame([b], columns=['f'+str(e) for e in range(len(b))])
                    bert_df.to_csv(data_dir+"/folds/"+str(fold)+"/bert.csv", mode='a+', index=False, header=False)

                #stops the bert-as-a-service server
                #shut_args = get_shutdown_parser().parse_args(['-ip','localhost','-port','5555','-timeout','5000'])
                #server.shutdown(shut_args)

            except Exception as e:
                print(traceback.format_exc())
                input("Error occured while fine training BERT. Press any key to exit.")
                sys.exit(1)

            print("BERT Embeddings Saved")
            savehash("bert", df_hash)

        #########################################
        ## CONCATENATION, SHUFFLING AND SAVING ##
        #########################################

        #if not check_hash(df_hash, num_folds, stage="concat"):
        if flag_concat:
            features = read_p(data_dir+"/features")
            features = np.delete(features,drop_feat_idx,axis=1)

            #normalize features
            features = np.nan_to_num(features)
            features_t = features.T
            for c in range(features_t.shape[0]):
                row = features_t[c]
                features_t[c] = np.interp(row, (np.min(row), np.max(row)), (-2, +2))
            features = features_t.T
            #delete labels and folds folders
            for i in range(num_folds):
                subprocess.call("rm -rf "+data_dir+"/folds/"+str(i)+"/labels", shell=True, cwd=data_dir)
                subprocess.call("rm -rf "+data_dir+"/folds/"+str(i)+"/features+bert.csv", shell=True, cwd=data_dir)
                subprocess.call("rm -rf "+data_dir+"/folds/"+str(i)+"/bert", shell=True, cwd=data_dir)
                subprocess.call("rm -rf "+data_dir+"/folds/"+str(i)+"/only_bert", shell=True, cwd=data_dir)

            #creates the shuffle order (not random)
            index_shuf = list(range(len(df)))

            #LABELS
            labels = [label_to_oh[label].tolist() for label in df['verdict'].values.tolist()]
            labels = [labels[i] for i in index_shuf]
            label_folds = np.array_split(labels, num_folds)

            for i in range(num_folds):
                fold_dir = data_dir+"/folds/"+str(i)
                if not os.path.exists(fold_dir):
                    os.mkdir(fold_dir)
                save_p(fold_dir+"/labels", label_folds[i])

            #creates a list of N=folds lists, each inner list contains the index of the elements of each fold
            bert_folds = np.array_split(index_shuf, num_folds)
            bert_folds = [a.tolist() for a in bert_folds]

            #creates an ordered list of N=entries of integers(:folds) indicating the fold idx of each entry
            fold_idx = [bert_folds.index(list(sl)) for e in index_shuf for sl in bert_folds if e in list(sl)]

            #TODO make this process read only one fold at a time
            for fold in range(num_folds):
                b_fold_csv = pd.read_csv(data_dir+"/folds/"+str(fold)+"/bert.csv", header=None)
                #gets only the indexes
                count = sum([1 for fidx,_ in zip(fold_idx, index_shuf) if fold == fidx])
                for idx in range(count):
                    b = b_fold_csv.iloc[idx]
                    entry = np.concatenate((features[idx,:],b))

                    feat_df = pd.DataFrame([entry], columns=['f'+str(e) for e in range(len(entry))])
                    feat_df.to_csv(data_dir+"/folds/"+str(fold)+"/features+bert.csv", mode='a+', index=False, header=False)

            for i in range(num_folds):
                fold_dir = data_dir+"/folds/"+str(i)
                bert = np.genfromtxt(fold_dir+"/features+bert.csv", delimiter=',')
                only_bert = np.genfromtxt(fold_dir+"/bert.csv", delimiter=',')
                print("saving bert fold ",str(i), bert.shape)
                save_p(fold_dir+"/bert", bert)
                save_p(fold_dir+"/only_bert", only_bert)

            print("MEMORY AFTER FOLDS SAVING: ",resource.getrusage(resource.RUSAGE_SELF).ru_maxrss)

            savehash("concat", hashcode=df_hash)

        checks = ["bert", "features", "concat"]
        if "inf" in feature_list: checks.append("complexity")
        if "spe" in feature_list: checks.append("specificity")

        for e in checks:
            print(e)
            print(check_hash(df_hash,num_folds,stage=e))
            if not (check_hash(df_hash,num_folds,stage=e, drop_feat_idx=drop_feat_idx)):
                print('Problem at Generation of data!')
                print("Stage: "+e)
                return

        print('Generation of data successfully done!')
        savehash("data", hashcode=df_hash)
        savehash("folds", hashcode=str(num_folds))

        return load_data(emb_type=emb_type, collapse_classes=collapse_classes, fold_test=fold_test, num_folds=num_folds, random_state=random_state, drop_feat_idx=drop_feat_idx, only_claims=only_claims)

    #check_hash is true
    else:
        print("Reading already processed data")
        #returns the selected emb type (bert/w2v)
        test_data = read_p(data_dir+"/folds/"+str(fold_test)+"/"+emb_type)
        test_target = read_p(data_dir+"/folds/"+str(fold_test)+"/labels")

        dev_data = read_p(data_dir+"/folds/"+str(fold_dev)+"/"+emb_type)
        dev_target = read_p(data_dir+"/folds/"+str(fold_dev)+"/labels")

        train_data_filenames = [data_dir+"/folds/"+str(i)+"/"+emb_type for i in range(num_folds) if i not in [fold_test,fold_dev]]
        train_data = np.concatenate([read_p(fn) for fn in train_data_filenames], axis=0)
        train_target_filenames = [data_dir+"/folds/"+str(i)+"/labels" for i in range(num_folds) if i not in [fold_test,fold_dev]]
        train_target = np.concatenate([read_p(fn) for fn in train_target_filenames], axis=0)

        return train_data, train_target, dev_data, dev_target, test_data, test_target, label_to_oh


import logbook
import re
import requests
import requests.exceptions
import sys
import time

# LOGGING #
app_log = logbook.Logger('Movie Query App')

URL = 'http://movie_service.talkpython.fm/api/search/'

def get_query() -> str:
    user_query = input('What movie do you want to search for?: ')
    if not user_query or not user_query.strip():
        raise ValueError('Please enter search text.')
    return user_query

def get_movie_titles(search_query : str) -> list:
    try:
        # LOGGING #
        # start time of query
        start_time = time.time()
        app_log.trace(f'Starting search for query: {search_query}')

        response = requests.get(URL + search_query)

        # LOGGING #
        # log response status code
        app_log.trace(f'Request over with status code {response.status_code}')

        title_pattern = re.compile(r"\"title[\"\:\s]+([\w\s\-'\.]+)")
        title_search = title_pattern.findall(response.text)

        year_pattern = re.compile(r"\"year[\"\:\s]+(\d*)\,")
        year_search = year_pattern.findall(response.text)

        if not title_search:
            raise ValueError('No movie found')

        movie_list = zip(year_search, title_search)
        year_movie_list = sorted(movie_list, key=lambda x: x[0], reverse=True)

        # LOGGING #
        # time required for query completion
        end_time = time.time()
        app_log.trace(f'Finished search for query: {search_query}: ' + \
                f'{len(year_movie_list)} results in {int((end_time - start_time) * 1000)} ms')

        return year_movie_list

    except requests.exceptions.ConnectionError:
        raise ConnectionError('Your network is down')

def main():
    try:
        user_query = get_query()
        movie_list = get_movie_titles(user_query)
        for year, movie in movie_list:
            print(f'{year}: {movie}')
    except Exception as e:
        e_class = e.__class__.__name__
        e_msg = str(e)

        # LOGGING #
        # WARN if ConnectionError or ValueError
        if e_class == 'ConnectionError' or e_class == 'ValueError':
            app_log.warn(e_msg)
        else:
            app_log.exception(e_msg)

        print(e_msg)

# LOGGING #
def init_logging(filename=None):
    level = logbook.TRACE

    # new logfile if date change
    if filename:
        handler = logbook.TimedRotatingFileHandler(filename, level=level)
    else:
        handler = logbook.StreamHandler(sys.stdout, level=level)
    handler.push_application()

    if filename:
        msg = f'Logging initialized, level: {level}, mode: file_mode: {filename}'
    else:
        msg = f'Logging initialized, level: {level}, mode: stdout_mode'
    logger = logbook.Logger('Startup')
    logger.notice(msg)

if __name__=='__main__':
    # LOGGING #
    init_logging('movie-query.log')

    main()


from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, HttpResponseRedirect, reverse, get_object_or_404

from .forms import ProductForms
from .models import Product

@login_required
def ekle(request):
    form = ProductForms()
    if request.method == 'POST':
        form = ProductForms(data=request.POST, files=request.FILES)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.save()

            # Tags save
            form.save_m2m()

            messages.success(request, "İlanınız başarıyla oluşturuldu.")
            return HttpResponseRedirect(reverse('product-detay', kwargs={'pk': post.pk}))
    context = {'form': form}
    return render(request, 'product/ekle-guncelle.html', context=context)

def listele(request):
    posts = Product.objects.all()
    context = {'posts': posts}
    return render(request, 'product/listele.html', context=context)

@login_required
def guncelle(request, pk):
    data = get_object_or_404(Product, pk=pk)
    form = ProductForms(instance=data)

    # Gönderi kullanıcıya ait mi -> kontrol et
    if data.author != request.user:
        messages.warning(request, "Bu gönderi size ait değil.")
        return HttpResponseRedirect(reverse('anasayfa'))
        # raise ValidationError("Bu gönderi size ait değil.")

    if request.method == 'POST':
        form = ProductForms(instance=data, data=request.POST, files=request.FILES)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.save()

            # Tags update
            form.save_m2m()

            messages.success(request, "İlanınız başarıyla güncelleştirildi.")
            return HttpResponseRedirect(reverse('product-detay', kwargs={'pk': post.pk}))
    context = {'form': form}
    return render(request, 'product/ekle-guncelle.html', context=context)

@login_required
def sil(request, pk):
    post = get_object_or_404(Product, pk=pk)

    # Gönderi kullanıcıya ait mi -> kontrol et
    if post.author != request.user:
        messages.warning(request, "Bu gönderi size ait değil.")
        return HttpResponseRedirect(reverse('anasayfa'))

    post.delete()
    messages.warning(request, "İlanınız silindi.")
    return HttpResponseRedirect(reverse('product-listele'))

@login_required
def detay(request, pk):
    post = get_object_or_404(Product, pk=pk)
    context = {'post': post}
    return render(request, 'product/detay.html', context=context)

def anasayfa(request):
    return render(request, 'anasayfa.html')


from typing import Optional

from fastapi import FastAPI, HTTPException, Query

from celery_worker import app as celery
from tasks import sqrt_find
app = FastAPI()

@app.get("/")
def square_pens(value: str=Query(''),degree:int=Query(2)):
    print(type(value))
    result = if_int(value)
    if (result['status']):
        task = sqrt_find.delay(int(value),degree)
        print(task)
    else:
        raise HTTPException(status_code=400, detail=result['text'])
    return {"detail": "process start"}

def if_int(in_num: str) -> dict:
    """Функция проверяет является ли число уелым положительным
    in_num -- входная строка

    """
    try:
        if int(in_num) > 0:
            return {'status': True, 'text': "This is int"}
        else:
            return {'status': False, 'text': "This is int<0"}
    except ValueError:
        return {'status': False, 'text': "This is not int"}


import cv2
import os
import sys
from skimage import transform, util

directory = ""
result_dir = ""

# Get directory paths
if len(sys.argv) == 3:
    directory = sys.argv[1]
    result_dir = sys.argv[2]
else:
    exit("Usage: downscale_images.py input_dataset_path output_dataset_path")

# Iterate over all child directory names
child_dirs = next(os.walk(directory))[1]
for child_dir in child_dirs:
    # Iterate over all images in the given directory
    for filename in os.listdir(directory + "/" + child_dir):
        # If file is a jpg or png image
        if filename.endswith(".jpg") or filename.endswith(".png"):
            # Get image from filename
            original = cv2.imread(directory + "/" + child_dir + "/" + filename, cv2.IMREAD_COLOR)
            orig_scikit = util.img_as_float(original)

            # Get vertically flipped image
            vflipped = cv2.flip(original, flipCode=0)

            # Get horizontally flipped image
            hflipped = cv2.flip(original, flipCode=0)

            # Get rotated images by 30 degrees
            rot30 = transform.rotate(orig_scikit, angle=30)

            # Add noise
            noisy = util.random_noise(orig_scikit)

            # Blur image
            blurry = cv2.GaussianBlur(orig_scikit, (5,5), 0)

            # Output all images
            cv2.imwrite(result_dir + "/" + child_dir + "/" + filename, original)
            cv2.imwrite(os.path.splitext(result_dir + "/" + child_dir + "/" + filename)[0] + "_vflipped.jpg", vflipped)
            cv2.imwrite(os.path.splitext(result_dir + "/" + child_dir + "/" + filename)[0] + "_hflipped.jpg", hflipped)
            cv2.imwrite(os.path.splitext(result_dir + "/" + child_dir + "/" + filename)[0] + "_rot30.jpg", util.img_as_ubyte(rot30))
            cv2.imwrite(os.path.splitext(result_dir + "/" + child_dir + "/" + filename)[0] + "_noisy.jpg", util.img_as_ubyte(noisy))
            cv2.imwrite(os.path.splitext(result_dir + "/" + child_dir + "/" + filename)[0] + "_blurry.jpg", util.img_as_ubyte(blurry))


"""full_cost URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import include, path
from lab.views import Index

urlpatterns = [
    path('', Index.as_view(), name='index'),
    path('lab/', include('lab.urls')),
    path('osp/', include('osp.urls')),
    path('met/', include('met.urls')),
    path('prepa/', include('prepa.urls')),
    path('fib/', include('fib.urls')),
    path('mphys/', include('mphys.urls')),
    path('chem/', include('chem.urls')),
    path('imag/', include('imag.urls')),
    path('fab/', include('fab.urls')),
    path('engi/', include('engi.urls')),
    path('admin/', admin.site.urls),
    path('accounts/', include('django.contrib.auth.urls')),
]


import graphviz

class Tree():

    # Constructor, no se manda ningun parametro
    def __init__(self):
        self.grafo = ""
        self.contador = 0
        self.dot = graphviz.Digraph(name="grafo", format='svg')
        self.dot.attr('node', shape='box')

    # Generamos la estructura inicial del documento dot
    def getDot(self, raiz):
        self.grafo = 'digraph G{ '
        self.grafo += 'node[shape="box"]; '
        self.contador = 1
        self.grafo += self.graficarNodo(raiz)
        self.grafo += '}'
        return self.grafo, self.dot

    # Funcion recursiva capaz de recorrer el arbol e ir generando el codigo necesario para poder graficar
    def graficarNodo(self, nodo):
        cadena = ""
        if nodo != None:
            for hijos in nodo.hijos:
                nodoPadre = ''
                nodoHijo = ''
                nodoPadre = '"' + nodo.getNumero() + "_" + nodo.getNombre() + '"' + '[label = "' + nodo.getValor() + '"];'
                nodoHijo = '"' + hijos.getNumero() + "_" + hijos.getNombre() + '"' + '[label = "' + hijos.getValor() + '"];'
                apuntadorPadre = '"' + nodo.getNumero() + "_" + nodo.getNombre() + '"'
                apuntadorHijo = '"' + hijos.getNumero() + "_" + hijos.getNombre() + '"'
                cadena += nodoPadre + ' ' + nodoHijo + ' ' + apuntadorPadre + '->' + apuntadorHijo + '; '
                self.dot.node(nodo.getNumero() + "_" + nodo.getNombre(), nodo.getValor())
                self.dot.node(hijos.getNumero() + "_" + hijos.getNombre(), hijos.getValor())
                self.dot.edge(nodo.getNumero() + "_" + nodo.getNombre(), hijos.getNumero() + "_" + hijos.getNombre())
                cadena += self.graficarNodo(hijos)
        return cadena


from django.shortcuts import render
from.models import FeedbackData,ContactData,CoursesData
from .forms import FeedbackForm,ContactForm
from django.http import HttpResponse
import  datetime
date1=datetime.datetime.now()

def main_page(request):
    return  render(request,'Base.html')

def home_page(request):
    return render(request,'home.html')

#if we want to select multiple fileds at a time and store in the database .."use Cleaned_data.get()"

def contact_page(request):

    if request.method == "POST":

        cform=ContactForm(request.POST)

        if cform.is_valid():

            name=cform.cleaned_data.get('name')
            email = cform.cleaned_data.get('email')
            mobile = cform.cleaned_data.get('mobile')
            courses = cform.cleaned_data.get('courses')
            shifts= cform.cleaned_data.get('shifts')
            locations = cform.cleaned_data.get('locations')
            gender = cform.cleaned_data.get('gender')
            start_date = cform.cleaned_data.get('start_date')

            data=ContactData(

                name=name,
                email=email,
                mobile=mobile,
                courses=courses,
                shifts=shifts,
                locations=locations,
                gender=gender,
                start_date=start_date
                )
            data.save()
            cform=ContactForm()

            return render(request,'contact.html',{'cform':cform})
        else:
            return HttpResponse('user invalid data')
    else:
         cform=ContactForm()
         return render(request,'contact.html',{'cform':cform})

# course_page view code

def course_page(request):
    courses=CoursesData.objects.all()
    return render(request,'course.html',{'courses':courses})

def ourteam_page(request):
    return render(request,'ourteam.html')

def gallery_page(request):
    return render(request,'gallery.html')

def feedback_page(request):
    if request.method=="POST":
        fform=FeedbackForm(request.POST)
        if fform.is_valid():
            name=request.POST.get('name')
            rating=request.POST.get('rating')
            feedback=request.POST.get('feedback')
            data=FeedbackData(
                name=name,
                rating=rating,
                feedback=feedback,
                date=date1
            )
            data.save()
            fform=FeedbackForm()
            fdata=FeedbackData.objects.all()
            return render(request, 'feedback.html', {'fform': fform,'fdata':fdata})
        else:
            return HttpResponse('Invalid User data')

    else:
        fform=FeedbackForm()
        fdata=FeedbackData.objects.all()
        return render(request,'feedback.html',{'fform':fform,'fdata':fdata})

# this code is Rajareddy

# def feedback_page(request):
#     if request.method =='POST':
#         fform=FeedbackForm(request.POST)
#         if fform.is_valid():
#             name=request.POST.get('name')
#             rating=request.POST.get('rating')
#             feedback=request.POST.get('feedback')
#             data=FeedbackData(
#                 name=name,
#                 rating=rating,
#                 feedback=feedback
#             )
#             data.save()
#             fform=FeedbackForm()
#             fdata=FeedbackData.objects.all()
#             return render(request,'feedback.html',{'fform':fform},{'fdata':fdata})
#         else:
#             return HttpResponse('invalid user data')
#     else:
#
#         fform = FeedbackForm()
#         fdata=FeedbackData.objects.all()
#         return render(request,'feedback.html',{'fform':fform},{'fdata':fdata})


import datetime
from odonto.odonto_submissions.serializers import translate_to_bdcs1
from fp17 import treatments, exemptions

def annotate(bcds1):
    bcds1.patient.surname = "CAMPBELL"
    bcds1.patient.forename = "PAUL"
    bcds1.patient.address = ["39 HIGH STREET"]
    bcds1.patient.sex = 'M'
    bcds1.patient.date_of_birth = datetime.date(1970, 9, 1)

    bcds1.date_of_acceptance = datetime.date(2017, 4, 1)
    bcds1.date_of_completion = datetime.date(2017, 4, 1)

    # "Employment Support Allowance"
    bcds1.exemption_remission = {
        'code': exemptions.INCOME_RELATED_EMPLOYMENT_AND_SUPPORT_ALLOWANCE.EVIDENCE_SEEN,
    }

    # Treatments: "Extraction 1"
    bcds1.treatments = [
        treatments.TREATMENT_CATEGORY(2),
    ]

    return bcds1

def from_model(bcds1, patient, episode):
    demographics = patient.demographics()
    demographics.surname = "CAMPBELL"
    demographics.first_name = "PAUL"
    demographics.house_number_or_name = "39"
    demographics.street = "HIGH STREET"
    demographics.sex = "Male"
    demographics.date_of_birth = datetime.date(1970, 9, 1)
    demographics.save()

    episode.fp17treatmentcategory_set.update(
        treatment_category="Band 2",
    )

    episode.fp17exemptions_set.update(
        income_related_employment_and_support_allowance=True,
        evidence_of_exception_or_remission_seen=True
    )

    episode.fp17incompletetreatment_set.update(
        date_of_acceptance=datetime.date(2017, 4, 1),
        completion_or_last_visit=datetime.date(2017, 4, 1)
    )

    translate_to_bdcs1(bcds1, episode)