class Test(unittest.TestCase):
    def setUp(self):
        self.world = World(None)
        self.world.start()
        
        
    def testWorld(self):
        self.world.loader.filename = 'ballformation.sim'
        self.world.loadSimulation(True)
        amount = len(self.world.objects)
        first_item = self.world.objects.keys()[0]
        self.world.deleteObject(first_item)
        amount2 = len(self.world.objects)
        self.assertEqual(amount-1, amount2)
        
        self.world.addObject(AstronomicalObject(vector(0,0,0), vector(0,0,0),0,sphere(position=(0,0,0), make_trail=False),0), 'newObject')
        self.assertEqual(len(self.world.objects), amount)
        self.world.close()
        scene.visible = 0

    def testSimulation(self):
        self.world.loader.filename = 'ballformation.sim'
        self.world.loadSimulation(True)
        self.world.startSimulation()
        sleep(3)
        self.world.stopSimulation()
class ControlWindow(QtGui.QWidget):
    def __init__(self):
        super(ControlWindow, self).__init__()
        self.world = World(self)
        self.simulation_on = False  # used to set the simulation speed display to zero if False
        self.add_object_window = None
        self.selector = None
        self.collision = False
        self.collision_text = ''
        self.initUI()

    def initUI(self):

        self.setGeometry(820, 30, 300, 0)
        self.setWindowTitle('Control Window')

        # create informational elements
        self.statusbar = QtGui.QStatusBar(self)
        self.statusbar.showMessage('Ready')
        self.sim_speed_label = QtGui.QLabel('Simulation speed: ')
        self.sim_speed_value = QtGui.QLabel('0 /s')
        velocity_scale = QtGui.QLabel('Velocity scale')
        acceleration_scale = QtGui.QLabel('Acceleration scale')
        self.reference_label = QtGui.QLabel('Default')
        
        # create control elements
        # buttons
        btn_start = QtGui.QPushButton('Start/Stop', self)
        btn_load = QtGui.QPushButton('Load simulation', self)
        btn_reload = QtGui.QPushButton('Reload simulation', self)
        btn_clear = QtGui.QPushButton('Clear', self)
        btn_camera = QtGui.QPushButton('Camera', self)
        
        # sliders
        velocity_vector_scale = QtGui.QSlider(QtCore.Qt.Horizontal, self)
        acceleration_vector_scale = QtGui.QSlider(QtCore.Qt.Horizontal, self)
        acceleration_vector_gain = QtGui.QSlider(QtCore.Qt.Horizontal, self)  # sets the gain value for acceleration
        acceleration_vector_gain.setMinimum(1)
        acceleration_vector_gain.setMaximum(100000)

        # add object window
        self.add_object_window = AddObjectWindow(self.world)

        # time step settings
        timestep_label = QtGui.QLabel('Timestep:')
        self.timestep_value_label = QtGui.QLabel('{}'.format(self.world.getTimeStep()))
        timestep_set_button = QtGui.QPushButton('Set', self)
        self.timestep_edit = QtGui.QLineEdit(self)

        # checkboxes
        self.chkbx_trails = QtGui.QCheckBox('Show trails', self)
        self.chkbx_vectors = QtGui.QCheckBox('Show vectors', self)

        # set timers
        self.speedtimer = QtCore.QTimer()   # updates the updates per second value
        self.speedtimer.setInterval(1000)
        self.speedtimer.start()
        
        # set widget layout
        grid = QtGui.QGridLayout()
        grid.addWidget(btn_start, 0, 0)
        grid.addWidget(btn_load, 0, 1)
        grid.addWidget(btn_reload, 0, 2)
        grid.addWidget(btn_clear, 0, 3)
        
        grid.addWidget(self.sim_speed_label, 1, 0)
        grid.addWidget(self.sim_speed_value, 1, 1)
        
        grid.addWidget(timestep_label, 3,0)
        grid.addWidget(self.timestep_value_label, 3, 1)
        grid.addWidget(self.timestep_edit, 3, 2)
        grid.addWidget(timestep_set_button, 3, 3)
        
        grid.addWidget(self.chkbx_trails, 4,0)
        grid.addWidget(btn_camera, 4, 2)
        grid.addWidget(self.reference_label, 4, 3)
        grid.addWidget(self.chkbx_vectors, 4, 1)

        grid.addWidget(velocity_scale, 6,0)
        grid.addWidget(velocity_vector_scale, 6,1)
        grid.addWidget(acceleration_scale, 7, 0)
        grid.addWidget(acceleration_vector_scale, 7, 1)
        grid.addWidget(acceleration_vector_gain, 7, 2)
        grid.addWidget(self.add_object_window,8,0,1,-1)
        grid.addWidget(self.statusbar, 9,0,1,-1)

        
        self.setLayout(grid)


        # set button tooltips
        btn_start.setToolTip('Start/pause simulation')
        timestep_set_button.setToolTip('Set simulation timestep')
        btn_clear.setToolTip('Clear all objects')

        # connect controls
        btn_load.clicked.connect(self.loadSimulation)
        btn_reload.clicked.connect(self.reloadSimulation)
        btn_start.clicked.connect(self.startStop)
        btn_clear.clicked.connect(self.clearObjects)
        btn_camera.clicked.connect(self.openObjectSelector)
        self.chkbx_trails.stateChanged.connect(self.showTrails)
        self.chkbx_vectors.stateChanged.connect(self.showVectors)
        timestep_set_button.clicked.connect(self.setTimeStep)
        velocity_vector_scale.valueChanged.connect(self.world.setVelocityVectorScale)
        acceleration_vector_scale.valueChanged.connect(self.world.setAccelerationVectorScale)
        acceleration_vector_gain.valueChanged.connect(self.world.setAccelerationGain)

        
        # connect timer
        self.speedtimer.timeout.connect(self.setSimSpeedDisplay)

        # set visible
        self.show()


        
    def start(self):    # call the start method of the World object to start the thread
        self.world.start()

    def setTimeStep(self):
        try:
            self.world.setTimeStep(str(self.timestep_edit.text()))
        except ValueError:
            self.statusbar.showMessage('Invalid argument for timestep')
            return
        self.timestep_value_label.setText(self.timestep_edit.text())
        self.statusbar.showMessage('Ready')

    def setSimSpeedDisplay(self):
        if self.simulation_on:
            self.sim_speed_value.setText('{} /s'.format(self.world.speed))
        else:
            self.sim_speed_value.setText('0 /s')
        if self.collision:
            self.collision = False
            self.statusbar.showMessage(self.collision_text)
    
    def loadSimulation(self):
        self.simulation_on = False
        self.world.stopSimulation()
        self.add_object_window.setReference('Default')
        self.world.loadSimulation()
        if self.world.errors == Loader.ERRORS_OCCURRED:
            self.statusbar.showMessage('Errors occurred when loading simulation. Check error log.')
        elif self.world.errors == Loader.OBJECTS_LOADED:
            self.statusbar.showMessage('Simulation loaded succesfully!')
        elif self.world.errors == Loader.OBJECTS_NOT_LOADED:
            self.statusbar.showMessage('Object loading canceled.')

    def reloadSimulation(self):
        self.simulation_on = False
        self.world.stopSimulation()
        self.add_object_window.setReference('Default')
        self.setReference('Default')
        self.world.reloadSimulation()
        if self.world.errors == Loader.ERRORS_OCCURRED:
            self.statusbar.showMessage('Errors occurred when loading simulation. Check error log.')
        elif self.world.errors == Loader.OBJECTS_LOADED:
            self.statusbar.showMessage('Simulation loaded succesfully!')
        elif self.world.errors == Loader.OBJECTS_NOT_LOADED:
            self.statusbar.showMessage('Object loading canceled.')
        elif self.world.errors == Loader.FILE_NOT_OPENED:       
            self.statusbar.showMessage('File could not be loaded.')

    def clearObjects(self):
        if  not self.world.paused:
            self.world.stopSimulation()
            self.simulation_on = False
        self.world.clearObjects()
        self.add_object_window.setReference('Default')
        self.setReference('Default')
        self.statusbar.showMessage('Objects cleared')

    def showTrails(self, state):
        if state == QtCore.Qt.Checked:
            self.world.showTrails(True)
        else:
            self.world.showTrails(False)

    def showVectors(self, state):
        if state:
            self.world.showVectors(True)
        else:
            self.world.showVectors(False)
        
    def startStop(self):    # start/pause simulation
        if  not self.world.paused:
            self.world.stopSimulation()
            self.simulation_on = False
            self.statusbar.showMessage('Simulation paused')
            print self.world.time_elapsed/86400
        else:
            self.world.startSimulation()
            self.simulation_on = True
            self.statusbar.showMessage('Simulation started')
            
    def reportCollision(self, error):
        #self.statusbar.showMessage(error)
        self.collision_text = error
        self.collision = True
        self.simulation_on = False

    def openObjectSelector(self):
        self.selector = ObjectSelector(self)

    def setReference(self, reference):
        if reference != 'Default':
            self.world.setReference(reference)
            self.reference_label.setText(reference)
        else:
            self.world.setReference(None)
            self.reference_label.setText('Default')

    def closeEvent(self, event):    # handle closing the program
        scene.visible = 0           # close the scenery window
        self.world.close()
        self.add_object_window.close() # this is necessary so that the reference selector will also close automatically
        if self.selector is not None:
            self.selector.close()
        self.close()
        event.accept()