class SimpleGUI(Plugin):
    
    # For sending speech
    sound_sig = Signal(SoundRequest)
    
    # Joints for arm poses
    joint_sig = Signal(JointState)
    

    def __init__(self, context):
        self.prompt_width = 170
        self.input_width = 250    
        
        super(SimpleGUI, self).__init__(context)
        self.setObjectName('SimpleGUI')
        self._widget = QWidget()     

        self._sound_client = SoundClient()
        
        #find relative path for files to load
        self.local_dir = os.path.dirname(__file__)
        self.dir = os.path.join(self.local_dir, './lib/rqt_simplegui/')
        if not os.path.isdir(self.dir):
            os.makedirs(self.dir)
        
        #need to add any additional subfolders as needed
        if not os.path.isdir(self.dir + 'animations/'):
            os.makedirs(self.dir + 'animations/')
        
 
        # Creates a subscriber to the ROS topic, having msg type SoundRequest 
        rospy.Subscriber('robotsound', SoundRequest, self.sound_cb)

        QtGui.QToolTip.setFont(QtGui.QFont('SansSerif', 10))
        self.sound_sig.connect(self.sound_sig_cb)
        
        # Code used for saving/ loading arm poses for the robot
        switch_srv_name = 'pr2_controller_manager/switch_controller'
        rospy.loginfo('Waiting for switch controller service...')
        rospy.wait_for_service(switch_srv_name)
        self.switch_service_client = rospy.ServiceProxy(switch_srv_name,
                                                 SwitchController)
                                                 
                                                 
        self.r_joint_names = ['r_shoulder_pan_joint',
                              'r_shoulder_lift_joint',
                              'r_upper_arm_roll_joint',
                              'r_elbow_flex_joint',
                              'r_forearm_roll_joint',
                              'r_wrist_flex_joint',
                              'r_wrist_roll_joint']
                              
        self.l_joint_names = ['l_shoulder_pan_joint',
                              'l_shoulder_lift_joint',
                              'l_upper_arm_roll_joint',
                              'l_elbow_flex_joint',
                              'l_forearm_roll_joint',
                              'l_wrist_flex_joint',
                              'l_wrist_roll_joint']

        self.all_joint_names = []
        self.all_joint_poses = []

        # Hash tables storing the name of the pose and the
        # associated positions for that pose, initially empty
        self.saved_l_poses = {}
        self.saved_r_poses = {}
        
        # Hash tables for storing name of animations and the associated pose list
        self.saved_animations = {}
        
        self.lock = threading.Lock()
        rospy.Subscriber('joint_states', JointState, self.joint_states_cb)
        
        #parsing for animations
        dir = os.path.dirname(__file__)
        qWarning(dir)
        filename = os.path.join(self.dir, 'animations/')

        ani_path = filename
        ani_listing = os.listdir(ani_path)
        for infile in ani_listing:
            pose_left = []
            pose_right = []
            left_gripper_states = []
            right_gripper_states = []
            line_num = 1
            for line in fileinput.input(ani_path + infile):
                if (line_num % 2 == 1):
                    pose = [float(x) for x in line.split()]
                    pose_left.append(pose[:len(pose)/2])
                    pose_right.append(pose[len(pose)/2:])
                else:
                    states = line.split()
                    left_gripper_states.append(states[0])
                    right_gripper_states.append(states[1])
                line_num += 1
            self.saved_animations[os.path.splitext(infile)[0]] = Quad(pose_left, pose_right, left_gripper_states, right_gripper_states)


        # Create a trajectory action client
        r_traj_controller_name = '/r_arm_controller/joint_trajectory_action'
        self.r_traj_action_client = SimpleActionClient(r_traj_controller_name, JointTrajectoryAction)
        rospy.loginfo('Waiting for a response from the trajectory action server for RIGHT arm...')
        self.r_traj_action_client.wait_for_server()
        
        l_traj_controller_name = '/l_arm_controller/joint_trajectory_action'
        self.l_traj_action_client = SimpleActionClient(l_traj_controller_name, JointTrajectoryAction)
        rospy.loginfo('Waiting for a response from the trajectory action server for LEFT arm...')
        self.l_traj_action_client.wait_for_server()

        # Navigation functionality initialization
        self.roomNav = RoomNavigator()


        self._tf_listener = TransformListener()
        self.animPlay = AnimationPlayer(None, None, None, None)

        # Detection and pickup functionality
        self.pap = PickAndPlaceManager(self._tf_listener, self.roomNav, self.animPlay)
        
        QtGui.QToolTip.setFont(QtGui.QFont('SansSerif', 10))
        self.joint_sig.connect(self.joint_sig_cb)
            
        # Create a large vertical box that is top aligned
        large_box = QtGui.QVBoxLayout()
        large_box.setAlignment(QtCore.Qt.AlignTop)
        large_box.setMargin(0)
        large_box.addItem(QtGui.QSpacerItem(10,0))

        # Buttons for controlling the head of the robot
        head_box = QtGui.QHBoxLayout()
        head_box.addItem(QtGui.QSpacerItem(230,0))
        head_box.addWidget(self.create_pressed_button('Head Up'))
        head_box.addStretch(1)
        large_box.addLayout(head_box)
    

        button_box = QtGui.QHBoxLayout()
        button_box.addItem(QtGui.QSpacerItem(80,0))
        button_box.addWidget(self.create_pressed_button('Head Turn Left'))
        button_box.addWidget(self.create_pressed_button('Head Down'))
        button_box.addWidget(self.create_pressed_button('Head Turn Right'))
        button_box.addStretch(1)
        button_box.setMargin(0)
        button_box.setSpacing(0)
        large_box.addLayout(button_box)
            
        # Shows what the robot says
        speech_box = QtGui.QHBoxLayout()

        self.speech_label = QtGui.QLabel('Robot has not spoken yet') 
        palette = QtGui.QPalette()
        palette.setColor(QtGui.QPalette.Foreground,QtCore.Qt.blue)
        self.speech_label.setPalette(palette) #
        speech_box.addItem(QtGui.QSpacerItem(100,0))
        #speech_box.addWidget(self.speech_label) #

        large_box.addLayout(speech_box)

        # Speak button
        speak_button_box = QtGui.QHBoxLayout();
        speech_prompt = QtGui.QLabel('Enter Speech Text:')
        speech_prompt.setFixedWidth(self.prompt_width)
        speak_button_box.addWidget(speech_prompt)
        robot_says = QtGui.QLineEdit(self._widget)
        robot_says.setFixedWidth(self.input_width)
        robot_says.textChanged[str].connect(self.onChanged) #
        speak_button_box.addWidget(robot_says)
        speak_button_box.addWidget(self.create_button('Speak'))
        speak_button_box.addStretch(1)
        large_box.addLayout(speak_button_box)

        large_box.addItem(QtGui.QSpacerItem(0,50)) 
       
        # Buttons for arm poses
        pose_button_box1 = QtGui.QHBoxLayout()
        pose_button_box1.addItem(QtGui.QSpacerItem(150,0))
        pose_button_box1.addWidget(self.create_button('Relax Left Arm'))
        pose_button_box1.addWidget(self.create_button('Relax Right Arm'))
        pose_button_box1.addStretch(1)
        large_box.addLayout(pose_button_box1)
        
        
        # Buttons for grippers
        gripper_button_box = QtGui.QHBoxLayout()
        gripper_button_box.addItem(QtGui.QSpacerItem(150,0))
        gripper_button_box.addWidget(self.create_button('Open Left Gripper'))
        gripper_button_box.addWidget(self.create_button('Open Right Gripper'))
        gripper_button_box.addStretch(1)
        large_box.addLayout(gripper_button_box)
        
        large_box.addItem(QtGui.QSpacerItem(0,25)) 
        
        # Buttons for animation
        animation_box = QtGui.QHBoxLayout()
        play_anim_label = QtGui.QLabel('Select Animation:')
        play_anim_label.setFixedWidth(self.prompt_width)
        animation_box.addWidget(play_anim_label)
        self.saved_animations_list = QtGui.QComboBox(self._widget)
        animation_box.addWidget(self.saved_animations_list)
        
        pose_time_label = QtGui.QLabel('Duration(sec):')
        pose_time_label.setFixedWidth(100)
        animation_box.addWidget(pose_time_label)
        self.pose_time = QtGui.QLineEdit(self._widget)
        self.pose_time.setFixedWidth(50)
        self.pose_time.setText('2.0')
        animation_box.addWidget(self.pose_time)
        
        animation_box.addWidget(self.create_button('Play Animation'))
        animation_box.addStretch(1)
        large_box.addLayout(animation_box)
        
        animation_box2 = QtGui.QHBoxLayout()
        animation_name_label = QtGui.QLabel('Enter Animation Name:')
        animation_name_label.setFixedWidth(self.prompt_width)
        animation_box2.addWidget(animation_name_label)
        self.animation_name = QtGui.QLineEdit(self._widget)
        self.animation_name.setFixedWidth(self.input_width)
        animation_box2.addWidget(self.animation_name)
        animation_box2.addWidget(self.create_button('Save Animation'))
        animation_box2.addStretch(1)
        large_box.addLayout(animation_box2)
        
        animation_box3 = QtGui.QHBoxLayout()
        pose_name_label = QtGui.QLabel('Enter Pose Name:')
        pose_name_label.setFixedWidth(self.prompt_width)
        animation_box3.addWidget(pose_name_label)
        self.pose_name_temp = QtGui.QLineEdit(self._widget)
        self.pose_name_temp.setFixedWidth(self.input_width)
        animation_box3.addWidget(self.pose_name_temp)
        animation_box3.addWidget(self.create_button('Add Current Pose'))
        animation_box3.addStretch(1)
        large_box.addLayout(animation_box3)
        
        # Playing around with UI stuff
        play_box = QtGui.QHBoxLayout()
        pose_sequence_label = QtGui.QLabel('Current Pose Sequence:')
        pose_sequence_label.setFixedWidth(self.prompt_width)
        pose_sequence_label.setAlignment(QtCore.Qt.AlignTop)
        
        self.list_widget = QListWidget()
        self.list_widget.setDragDropMode(QAbstractItemView.InternalMove)
        self.list_widget.setMaximumSize(self.input_width, 200)
        play_box.addWidget(pose_sequence_label)
        play_box.addWidget(self.list_widget)
        
        play_box.addStretch(1)
        large_box.addLayout(play_box)
        
        large_box.addItem(QtGui.QSpacerItem(0,50)) 
        
        # Buttons for first row of base controls
        first_base_button_box = QtGui.QHBoxLayout()
        first_base_button_box.addItem(QtGui.QSpacerItem(70,0))
        first_base_button_box.addWidget(self.create_pressed_button('Rotate Left'))
        first_base_button_box.addWidget(self.create_pressed_button('^'))
        first_base_button_box.addWidget(self.create_pressed_button('Rotate Right'))
        first_base_button_box.addStretch(1)
        large_box.addLayout(first_base_button_box)

        # Buttons for second row of base controls
        second_base_button_box = QtGui.QHBoxLayout()
        second_base_button_box.addItem(QtGui.QSpacerItem(70,0))
        second_base_button_box.addWidget(self.create_pressed_button('<'))
        second_base_button_box.addWidget(self.create_pressed_button('v'))
        second_base_button_box.addWidget(self.create_pressed_button('>'))
        second_base_button_box.addWidget(self.create_button('Move to Bin'))
        second_base_button_box.addWidget(self.create_button('Object Detect'))
        second_base_button_box.addWidget(self.create_button('Clean Room'))
        second_base_button_box.addStretch(1)
        large_box.addLayout(second_base_button_box)
        
        # Animation related items to store intermediate pose co-ordinates to save
        self.animation_map = {}
        
        self.create_state = False
        
        
        self._widget.setObjectName('SimpleGUI')
        self._widget.setLayout(large_box)
        context.add_widget(self._widget)

        # Look straight and down when launched
        self.head_x = 1.0
        self.head_y = 0.0
        self.head_z = 0.5
        self.head_action(self.head_x, self.head_y, self.head_z)

        # Set grippers to closed on initialization
        self.left_gripper_state = ''
        self.right_gripper_state = ''
        self.gripper_action('l', 0.0)
        self.gripper_action('r', 0.0)
    
        # Lab 6
        self.marker_publisher = rospy.Publisher('visualization_marker', Marker)
        
        # Saved states for poses
        saved_pose_box = QtGui.QHBoxLayout()
        self.saved_left_poses = QtGui.QLabel('')
        self.saved_right_poses = QtGui.QLabel('')
        
        saved_pose_box.addWidget(self.saved_left_poses)
        saved_pose_box.addWidget(self.saved_right_poses)
        large_box.addLayout(saved_pose_box)

        # Preload the map of animations
        self.saved_animations_list.addItems(self.saved_animations.keys())
        
        # Move the torso all the way down
        # self.torso_down(True)

        # Autonomous navigation stuff
        '''
        self.locations = [Pose(Point(2.48293590546, 3.90075874329, 0.000), Quaternion(0.000, 0.000, -0.783917630973, 0.620864838632)),
                         Pose(Point(3.70106744766, 0.304672241211, 0.000), Quaternion(0.000, 0.000, 0.950186880196, -0.311680754463)),
                         Pose(Point(2.57326722145, 1.51304531097, 0.000), Quaternion(0.000, 0.000, 0.96127194482, -0.275601611212)),
                         Pose(Point(1.28060531616, 1.52380752563, 0.000), Quaternion(0.000, 0.000, 0.946345258806, -0.323157316388)),
                         Pose(Point(2.11048603058, 0.420155525208, 0.000), Quaternion(0.000, 0.000, 0.945222393391, -0.326427062346)),
                         Pose(Point(2.82733058929, -0.739856719971, 0.000), Quaternion(0.000, 0.000, 0.945473998362, -0.325697587373)),
                         Pose(Point(1.29184818268, -1.90485572815, 0.000), Quaternion(0.000, 0.000, 0.942275557345, -0.334838429739)),
                         Pose(Point(0.722846984863, -1.0921459198, 0.000), Quaternion(0.000, 0.000, 0.949330143731, -0.314280572424))]
        '''
        self.locations = [Pose(Point(2.04748392105, 2.04748010635, 0.000), Quaternion(0.000, 0.000, -0.776968030817,  0.629540053601)),
                          Pose(Point(2.34193611145, 1.43208932877, 0), Quaternion(0, 0, -0.841674385779, 0.539985396398)),
                          Pose(Point(3.43202018738, -0.258297920227, 0.000), Quaternion(0.000, 0.000, 0.996656413122, -0.0817067572629)),
                          Pose(Point(0.931655406952, -1.96435832977, 0.000), Quaternion(0.000, 0.000, 0.691187586713, 0.722675390458)),
                          Pose(Point(-0.369112968445, 0.0330476760864, 0.000), Quaternion(0.000, 0.000, 0.0275340398899, 0.999620866453))]

        self.index = 1;

        rospy.loginfo("Completed GUI initialization")
        
    # Event for when text box is changed
    def onChanged(self, text):    
        self.speech_label.setText(text)
        self.speech_label.adjustSize()
        
    def sound_cb(self, sound_request):
        qWarning('Received sound.')
        self.sound_sig.emit(sound_request)
        
    def create_button(self, name):
        btn = QtGui.QPushButton(name, self._widget)
        btn.setFixedWidth(150)
        btn.clicked.connect(self.command_cb)
        return btn
    
    def create_pressed_button(self, name):
        btn = QtGui.QPushButton(name, self._widget)
        btn.setFixedWidth(150)
        btn.pressed.connect(self.command_cb)
        btn.setAutoRepeat(True) # To make sure the movement repeats itself
        return btn

    def sound_sig_cb(self, sound_request):
        qWarning('Received sound signal.')
        qWarning('Robot said: ' + sound_request.arg)
        self.speech_label.setText(sound_request.arg) #'Robot said: ' + 

	#a button was clicked
    def command_cb(self):
        button_name = self._widget.sender().text()
        
		#robot talk button clicked
        if (button_name == 'Speak'):
            qWarning('Robot will say: ' + self.speech_label.text() )
            self._sound_client.say(self.speech_label.text())
            self.show_text_in_rviz("Robot is Speaking")
		    
        #gripper button selected
        elif ('Gripper' in button_name):
            self.gripper_click(button_name)
        
        # Move forward
        elif (button_name == '^'):
            self.base_action(0.25, 0.0, 0.0, 0.0, 0.0, 0.0)

        # Move left
        elif (button_name == '<'):
            self.base_action(0.0, 0.25, 0.0, 0.0, 0.0, 0.0)     
        
        # Move right    
        elif (button_name == '>'):
            self.base_action(0.0, -0.25, 0.0, 0.0, 0.0, 0.0)
        
        # Move back
        elif (button_name == 'v'):
            self.base_action(-0.25, 0.0, 0.0, 0.0, 0.0, 0.0)

        #Rotate Left
        elif (button_name == 'Rotate Left'):
            self.base_action(0.0, 0.0, 0.0, 0.0, 0.0, 0.50)

        # Rotate Right
        elif (button_name == 'Rotate Right'):
            self.base_action(0.0, 0.0, 0.0, 0.0, 0.0, -0.50)   

        # A head button selected
        elif ('Head' in button_name):
            self.rotate_head(button_name)
        
        #An arm button selected
        #third param unused in freeze/relax
        #Second word in button should be side
        elif ('Arm' in button_name):

            arm_side = button_name.split()[1]
            
            if ('Freeze' in button_name or 'Relax' in button_name):
                new_arm_state = button_name.split()[0]
                self.toggle_arm(arm_side[0].lower(), new_arm_state, True)
                
                old_arm_state = ''
                if (new_arm_state == 'Relax'):
                    old_arm_state = 'Freeze'
                else:
                    old_arm_state = 'Relax'
                
                self._widget.sender().setText('%s %s Arm' % (old_arm_state, arm_side))
        
        elif('Play Animation' == button_name):
            self.animPlay.left_poses = self.saved_animations[self.saved_animations_list.currentText()].left
            self.animPlay.right_poses = self.saved_animations[self.saved_animations_list.currentText()].right
            self.animPlay.left_gripper_states = self.saved_animations[self.saved_animations_list.currentText()].left_gripper
            self.animPlay.right_gripper_states = self.saved_animations[self.saved_animations_list.currentText()].right_gripper
            if self.pose_time.text() == '':
                self.show_warning('Please enter a duration in seconds.')
            else:
                self.animPlay.play(self.pose_time.text())
        
        elif('Animation' in button_name):
            if ('Save' in button_name):
                if self.animation_name.text() == '':
                    self.show_warning('Please enter name for animation')
                else:
                    self.save_animation(self.animation_name.text())
                    self.list_widget.clear()
                    self.animation_name.setText('')
                
        elif('Add Current Pose' == button_name):
            if self.pose_name_temp.text() == '':
                self.show_warning('Insert name for pose')
            else:
                self.animation_map[self.pose_name_temp.text()] = Quad(self.get_joint_state('l'), self.get_joint_state('r'), self.left_gripper_state, self.right_gripper_state)
                list_item = QListWidgetItem()
                list_item.setText(self.pose_name_temp.text())
                self.list_widget.addItem(list_item) 
                self.pose_name_temp.setText('')  
                
        elif('Move to Bin' == button_name):
            self.move_to_bin_action()
        elif('Clean Room' == button_name):
            rospy.loginfo("STARTING AUTONOMOUS MODE")
            self.tuck_arms()

            while(self.index < len(self.locations)):
                self.roomNav.move_to_trash_location(self.locations[self.index])
                # self.index += 1
                
                self.head_action(1.0, 0, -0.50, True)
                # Returns Nonce if nothing, and the point of the first object it sees otherwise
                map_point = self.pap.detect_objects()
                
                if(map_point == None):
                    self.index += 1
                else:
                    self.pick_and_move_trash_action()
                
            rospy.loginfo("FINISHED AUTONOMOUS MODE")
            self.index = 1
            
        elif('Object Detect' == button_name):
            self.pick_and_move_trash_action()
            
    def pick_and_move_trash_action(self, map_point = None):
        if map_point == None:
            self.head_action(1.0, 0, -0.50, True)
            map_point = self.pap.detect_objects()

        if map_point == None:
            return
        
        # Convert to base link and move towards the object 0.50m away
        map_point = Transformer.transform(self._tf_listener, map_point.pose, map_point.header.frame_id, '/base_link')


        rospy.loginfo("Object is " + str (map_point.pose.position.x) + " away")
        '''
        if(map_point.pose.position.x < 0.8):
            self.roomNav.move_to_trash_location(self.locations[self.index - 1])
        '''
        move_back_first = False;
        if(map_point.pose.position.x < 0.7):
            move_back_first = True;

        map_point.pose.position.x -= 0.450
        map_point = Transformer.transform(self._tf_listener, map_point.pose, '/base_link', '/map')

        if(move_back_first):
            self.roomNav.move_to_trash_location(self.locations[self.index - 1])

        success = self.roomNav.move_to_trash_location(map_point.pose)
        
        '''This part of the code strafes the robot left to get closer to the object'''
        
        '''
        rate = rospy.Rate(10)
        position = Point()
        move_cmd = Twist()
        move_cmd.linear.y = 0.25
        odom_frame = '/odom_combined'
        
        # Find out if the robot uses /base_link or /base_footprint
        try:
            self._tf_listener.waitForTransform(odom_frame, '/base_footprint', rospy.Time(), rospy.Duration(1.0))
            self.base_frame = '/base_footprint'
        except (tf.Exception, tf.ConnectivityException, tf.LookupException):
           try:
               self._tf_listener.waitForTransform(odom_frame, '/base_link', rospy.Time(), rospy.Duration(1.0))
               self.base_frame = '/base_link'
           except (tf.Exception, tf.ConnectivityException, tf.LookupException):
               rospy.loginfo("Cannot find transform between " + odom_frame + " and /base_link or /base_footprint")
               rospy.signal_shutdown("tf Exception")
        
            # Get current position
            position = self.get_odom()
            
            x_start = position.x
            y_start = position.y
            
            # Distance travelled
            distance = 0
            goal_distance = 0.25
            rospy.loginfo("Strafing left")
            # Enter the loop to move along a side
            while distance < goal_distance:
                rospy.loginfo("Distance is at " + str(distance))
                # Publish the Twist message and sleep 1 cycle
                self.base_action(0, 0.25, 0, 0, 0, 0)
                rate.sleep()
                
                # Get the current position
                position = self.get_odom()
                
                # Compute the Euclidean distance from the start
                distance = abs(position.y - y_start) 
        '''
       
        if(success):
            # Move head to look at the object, this will wait for a result
            self.head_action(0, 0.4, 0.55, True)

            # Move arms to ready pickup position, this will wait for a result before trying to detect and pick up object
            self.animPlay.left_poses = self.saved_animations['ready_pickup'].left
            self.animPlay.right_poses = self.saved_animations['ready_pickup'].right
            self.animPlay.left_gripper_states = self.saved_animations['ready_pickup'].left_gripper
            self.animPlay.right_gripper_states = self.saved_animations['ready_pickup'].right_gripper
            self.animPlay.play('3.0')

            for i in range (0,3):
                success = self.pap.detect_and_pickup()
                # Move head back to look forward
                # Move head to look at the object, this will wait for a result
                self.head_action(1.0, 0.0, 0.55, True)
                if success:
                    break
            
            # Move to bin
            self.move_to_bin_action()


    
    def get_odom(self):
        # Get the current transform between the odom and base frames
        try:
            trans = self._tf_listener.lookupTransform('/odom_combined', self.base_frame, rospy.Time(0))
        except (tf.Exception, tf.ConnectivityException, tf.LookupException):
            rospy.loginfo("TF Exception")
            return
            
        return Point(trans[0][0],trans[0][1],trans[0][2])
                    
    # gripper_type is either 'l' for left or 'r' for right
    # gripper position is the position as a parameter to the gripper goal
    def gripper_action(self, gripper_type, gripper_position):
        name_space = '/' + gripper_type + '_gripper_controller/gripper_action'
        
        gripper_client = SimpleActionClient(name_space, GripperCommandAction)
        gripper_client.wait_for_server()
        gripper_goal = GripperCommandGoal()
        gripper_goal.command.position = gripper_position 
        gripper_goal.command.max_effort = 30.0
        gripper_client.send_goal(gripper_goal)
        # update the state of the current gripper being modified
        if (gripper_type == 'l'):
            if (gripper_position == 0.0):
                self.left_gripper_state = 'closed'
            else:
                self.left_gripper_state = 'open'
        else:
            if (gripper_position == 0.0):
                self.right_gripper_state = 'closed'
            else:
                self.right_gripper_state = 'open'
        
    def base_action(self, x, y, z, theta_x, theta_y, theta_z):
        topic_name = '/base_controller/command'
        base_publisher = rospy.Publisher(topic_name, Twist)

        twist_msg = Twist()
        twist_msg.linear = Vector3(x, y, z)
        twist_msg.angular = Vector3(theta_x, theta_y, theta_z)
        
        base_publisher.publish(twist_msg)

    # Moves the torso of the robot down to its maximum
    def torso_down(self, wait = False):
    	self.torso_client = SimpleActionClient('/torso_controller/position_joint_action', SingleJointPositionAction)
    	torso_goal = SingleJointPositionGoal()
    	torso_goal.position = 0.0
    	torso_goal.min_duration = rospy.Duration(5.0)
    	torso_goal.max_velocity = 1.0
    	self.torso_client.send_goal(torso_goal)
        if wait:
            # wait for the head movement to finish before we try to detect and pickup an object
            finished_within_time = self.torso_client.wait_for_result(rospy.Duration(15))
            # Check for success or failure
            if not finished_within_time:
                self.torso_client.cancel_goal()
                rospy.loginfo("Timed out achieving torso movement goal")
            else:
                state = self.torso_client.get_state()
                if state == GoalStatus.SUCCEEDED:
                    rospy.loginfo("Torso movement goal succeeded!")
                    rospy.loginfo("State:" + str(state))
                else:
                  rospy.loginfo("Torso movement goal failed with error code: " + str(state))

    def head_action(self, x, y, z, wait = False):
        name_space = '/head_traj_controller/point_head_action'
        head_client = SimpleActionClient(name_space, PointHeadAction)
        head_goal = PointHeadGoal()
        head_goal.target.header.frame_id = 'base_link'
        head_goal.min_duration = rospy.Duration(1.0)
        head_goal.target.point = Point(x, y, z)
        head_client.send_goal(head_goal)
        if wait:
            # wait for the head movement to finish before we try to detect and pickup an object
            finished_within_time = head_client.wait_for_result(rospy.Duration(5))
            # Check for success or failure
            if not finished_within_time:
                head_client.cancel_goal()
                rospy.loginfo("Timed out achieving head movement goal")
            else:
                state = head_client.get_state()
                if state == GoalStatus.SUCCEEDED:
                    rospy.loginfo("Head movement goal succeeded!")
                    rospy.loginfo("State:" + str(state))
                else:
                  rospy.loginfo("Head movement goal failed with error code: " + str(self.goal_states[state]))

    def tuck_arms(self):
        rospy.loginfo('Left tuck arms')
        self.animPlay.left_poses = self.saved_animations['left_tuck'].left
        self.animPlay.right_poses = self.saved_animations['left_tuck'].right
        self.animPlay.left_gripper_states = self.saved_animations['left_tuck'].left_gripper
        self.animPlay.right_gripper_states = self.saved_animations['left_tuck'].right_gripper
        self.animPlay.play('3.0')


    def move_to_bin_action(self):
        # First tuck arms
        self.tuck_arms()

        # Move to the bin
        rospy.loginfo('Clicked the move to bin button')
        self.roomNav.move_to_bin()
        # Throw the trash away
        rospy.loginfo('Throwing trash away with left arm')
        self.animPlay.left_poses = self.saved_animations['l_dispose'].left
        self.animPlay.right_poses = self.saved_animations['l_dispose'].right
        self.animPlay.left_gripper_states = self.saved_animations['l_dispose'].left_gripper
        self.animPlay.right_gripper_states = self.saved_animations['l_dispose'].right_gripper
        self.animPlay.play('2.0')
        # Tuck arms again
        self.tuck_arms()
            
    def shutdown_plugin(self):
        # TODO unregister all publishers here
        pass

    def save_settings(self, plugin_settings, instance_settings):
        # TODO save intrinsic configuration, usually using:
        # instance_settings.set_value(k, v)
        pass

    def restore_settings(self, plugin_settings, instance_settings):
        # TODO restore intrinsic configuration, usually using:
        # v = instance_settings.value(k)
        pass

    def show_text_in_rviz(self, text):
        marker = Marker(type=Marker.TEXT_VIEW_FACING, id=0,
                lifetime=rospy.Duration(1.5),
                pose=Pose(Point(0.5, 0.5, 1.45), Quaternion(0, 0, 0, 1)),
                scale=Vector3(0.06, 0.06, 0.06),
                header=Header(frame_id='base_link'),
                color=ColorRGBA(0.0, 1.0, 0.0, 0.8), text=text)
        self.marker_publisher.publish(marker)

    def show_arrow_in_rviz(self, arrow):
        marker = Marker(type=Marker.ARROW, id=0,
                lifetime=rospy.Duration(1.5),
                pose=Pose(Point(0.5, 0.5, 1.45), Quaternion(0, 0, 0, 1)),
                scale=Vector3(0.06, 0.06, 0.06),
                header=Header(frame_id='base_link'),
                color=ColorRGBA(0.0, 1.0, 0.0, 0.8), arrow=arrow)
        self.marker_publisher.publish(marker)
        
    def save_animation(self, animation_name):
        if animation_name != '':
            filename = os.path.join(self.dir, 'animations/')
            anim_file = open(filename + animation_name + '.txt', 'w')
            l_animation_queue = []
            r_animation_queue = []
            l_gripper_queue = []
            r_gripper_queue = []
            for i in range(self.list_widget.count()):
                item = self.list_widget.item(i)
                pose_name = item.text()
                anim_file.write(re.sub(',' , '', str(self.animation_map[pose_name].left).strip('[]') +
                                             ' ' + str(self.animation_map[pose_name].right).strip('[]')))
                anim_file.write('\n')
                anim_file.write(str(self.animation_map[pose_name].left_gripper) + ' ' + str(self.animation_map[pose_name].right_gripper))
                l_animation_queue.append(self.animation_map[pose_name].left)
                r_animation_queue.append(self.animation_map[pose_name].right)
                l_gripper_queue.append(self.animation_map[pose_name].left_gripper)
                r_gripper_queue.append(self.animation_map[pose_name].right_gripper)
                anim_file.write('\n')
            anim_file.close()
            
            self.saved_animations[animation_name] = Quad(l_animation_queue, r_animation_queue, l_gripper_queue, r_gripper_queue)
            self.saved_animations_list.addItem(animation_name) # Bug? Multiple entries
   
            # Reset the pending queue
            self.l_animation_queue = []
            self.r_animation_queue = []
        else:
            self.show_warning('Please insert name for animation')
                
                
    def gripper_click(self, button_name):
        grip_side = ''
        grip_side_text = ''
        
        if ('Left' in button_name):
            grip_side = 'l'
            grip_side_text = 'left'
        else:
            grip_side = 'r'
            grip_side_text = 'right'
            
        if ('Open' in button_name):
            grip_action = 20.0
            grip_action_text = 'close'
            qWarning('Robot opened %s gripper' % (grip_side_text))
        else:
            grip_action = 0.0
            grip_action_text = 'open'
            qWarning('Robot closed %s gripper' % (grip_side_text))
            
        
        self.show_text_in_rviz("%sing %s Gripper" % (grip_action_text.capitalize(), grip_side_text.capitalize()))
        self.gripper_action(grip_side, grip_action)
        
        self._widget.sender().setText('%s %s Gripper' % (grip_action_text.capitalize(), grip_side_text.capitalize()))
            
    def rotate_head(self, button_name):
        if('Left' in button_name):
            #qWarning('x: %s, y: %s' % (self.head_x, self.head_y))
           
            if (self.head_x < -0.8 and self.head_y > 0.0):
                self.show_warning('Can\'t rotate anymore')

            elif (self.head_y < 0.0):
                self.head_x += 0.1
                self.head_y = -((1.0 - self.head_x ** 2.0) ** 0.5)
                self.show_text_in_rviz("Turning Head Left")

            else:
                self.head_x -= 0.1
                self.head_y = (1.0 - self.head_x ** 2.0) ** 0.5
                self.show_text_in_rviz("Turning Head Left")

            qWarning('x: %s, y: %s' % (self.head_x, self.head_y))
            self.head_action(self.head_x, self.head_y, self.head_z)
            
        elif('Up' in button_name):
            if (self.head_z <= 1.6):
                self.head_z += 0.1
                self.show_text_in_rviz("Moving Head Up")
                self.head_action(self.head_x, self.head_y, self.head_z)
            else:
                self.show_warning('Can\'t look up anymore')
        
        elif('Down' in button_name):
            if (self.head_z >= -2.2):
                self.head_z -= 0.1
                self.show_text_in_rviz("Moving Head Down")
                self.head_action(self.head_x, self.head_y, self.head_z)
            else:
                self.show_warning('Can\'t look down anymore') 
            
        else:
            #qWarning('x: %s, y: %s' % (self.head_x, self.head_y))
            if (self.head_x < -0.8 and self.head_y < 0.0):
                self.show_warning('Can\'t rotate anymore')

            elif (self.head_y > 0.0):
                self.head_x += 0.1
                self.head_y = (1.0 - self.head_x ** 2.0) ** 0.5
                self.show_text_in_rviz("Turning Head Right")
                
            else:
                self.head_x -= 0.1
                self.head_y = -((1.0 - self.head_x ** 2.0) ** 0.5)
                self.show_text_in_rviz("Turning Head Right")     
            
            #qWarning('x: %s, y: %s' % (self.head_x, self.head_y))
            self.head_action(self.head_x, self.head_y, self.head_z)

    def toggle_arm(self, side, toggle, button):
        controller_name = side + '_arm_controller'
        
        start_controllers = []
        stop_controllers = []
        if (toggle == 'Relax'):
            stop_controllers.append(controller_name)
        else:
            start_controllers.append(controller_name)
        self.set_arm_mode(start_controllers, stop_controllers)

    def set_arm_mode(self, start_controllers, stop_controllers):
        try:
            self.switch_service_client(start_controllers, stop_controllers, 1)
        except rospy.ServiceException:
            rospy.logerr('Could not change arm mode.')

    def joint_states_cb(self, msg):
        '''Callback function that saves the joint positions when a
            joint_states message is received'''
        self.lock.acquire()
        self.all_joint_names = msg.name
        self.all_joint_poses = msg.position
        self.joint_sig.emit(msg)
        self.lock.release()

    def joint_sig_cb(self, msg):
        pass

    def get_joint_state(self, side_prefix):
        '''Returns position for arm joints on the requested side (r/l)'''
        if side_prefix == 'r':
            joint_names = self.r_joint_names
        else:
            joint_names = self.l_joint_names

        if self.all_joint_names == []:
            rospy.logerr("No robot_state messages received yet!\n")
            return None
    
        positions = []
        self.lock.acquire()
        for joint_name in joint_names:
            if joint_name in self.all_joint_names:
                index = self.all_joint_names.index(joint_name)
                position = self.all_joint_poses[index]
                positions.append(position)
            else:
                rospy.logerr("Joint %s not found!", joint_name)
                self.lock.release()
                return None

        self.lock.release()
        return positions
    
    def show_warning(self, text):
        qWarning(text)
        msgBox = QMessageBox()
        msgBox.setText(text)
        msgBox.exec_()
예제 #2
0
class TextSearchFrame(QDockWidget):
    '''
    A frame to find text in the Editor.
    '''
    search_result_signal = Signal(str, bool, str, int)
    ''' @ivar: A signal emitted after search_threaded was started.
        (search text, found or not, file, position in text)
        for each result a signal will be emitted.
    '''
    replace_signal = Signal(str, str, int, str)
    ''' @ivar: A signal emitted to replace string at given position.
        (search text, file, position in text, replaced by text)
    '''
    def __init__(self, tabwidget, parent=None):
        QDockWidget.__init__(self, "Find", parent)
        self.setObjectName('SearchFrame')
        self.setFeatures(QDockWidget.DockWidgetMovable
                         | QDockWidget.DockWidgetFloatable)
        self._dockwidget = QFrame(self)
        self.vbox_layout = QVBoxLayout(self._dockwidget)
        self.layout().setContentsMargins(0, 0, 0, 0)
        self.layout().setSpacing(1)
        # frame with two rows for find and replace
        find_replace_frame = QFrame(self)
        find_replace_vbox_layout = QVBoxLayout(find_replace_frame)
        find_replace_vbox_layout.setContentsMargins(0, 0, 0, 0)
        find_replace_vbox_layout.setSpacing(1)
        find_replace_vbox_layout.addSpacerItem(
            QSpacerItem(1, 1, QSizePolicy.Expanding, QSizePolicy.Expanding))
        # create frame with find row
        find_frame = self._create_find_frame()
        find_replace_vbox_layout.addWidget(find_frame)
        rplc_frame = self._create_replace_frame()
        find_replace_vbox_layout.addWidget(rplc_frame)
        # frame for find&replace and search results
        self.vbox_layout.addWidget(find_replace_frame)
        self.vbox_layout.addWidget(self._create_found_frame())
        self.vbox_layout.addStretch(2024)
        self.setWidget(self._dockwidget)
        # intern search parameters
        self._tabwidget = tabwidget
        self.current_search_text = ''
        self.search_results = []
        self.search_results_fileset = set()
        self._search_result_index = -1
        self._search_recursive = False
        self._search_thread = None

    def _create_find_frame(self):
        find_frame = QFrame(self)
        find_hbox_layout = QHBoxLayout(find_frame)
        find_hbox_layout.setContentsMargins(0, 0, 0, 0)
        find_hbox_layout.setSpacing(1)
        self.search_field = EnchancedLineEdit(find_frame)
        self.search_field.setPlaceholderText('search text')
        self.search_field.textChanged.connect(self.on_search_text_changed)
        self.search_field.returnPressed.connect(self.on_search)
        find_hbox_layout.addWidget(self.search_field)
        self.search_result_label = QLabel(find_frame)
        self.search_result_label.setText(' ')
        find_hbox_layout.addWidget(self.search_result_label)
        self.find_button_back = QPushButton("<")
        self.find_button_back.setFixedWidth(44)
        self.find_button_back.clicked.connect(self.on_search_back)
        find_hbox_layout.addWidget(self.find_button_back)
        self.find_button = QPushButton(">")
        self.find_button.setDefault(True)
        # self.find_button.setFlat(True)
        self.find_button.setFixedWidth(44)
        self.find_button.clicked.connect(self.on_search)
        find_hbox_layout.addWidget(self.find_button)
        return find_frame

    def _create_replace_frame(self):
        # create frame with replace row
        self.rplc_frame = rplc_frame = QFrame(self)
        rplc_hbox_layout = QHBoxLayout(rplc_frame)
        rplc_hbox_layout.setContentsMargins(0, 0, 0, 0)
        rplc_hbox_layout.setSpacing(1)
        self.replace_field = EnchancedLineEdit(rplc_frame)
        self.replace_field.setPlaceholderText('replace text')
        self.replace_field.returnPressed.connect(self.on_replace)
        rplc_hbox_layout.addWidget(self.replace_field)
        self.replace_result_label = QLabel(rplc_frame)
        self.replace_result_label.setText(' ')
        rplc_hbox_layout.addWidget(self.replace_result_label)
        self.replace_button = replace_button = QPushButton("> &Replace >")
        replace_button.setFixedWidth(90)
        replace_button.clicked.connect(self.on_replace_click)
        rplc_hbox_layout.addWidget(replace_button)
        rplc_frame.setVisible(False)
        return rplc_frame

    def _create_found_frame(self):
        self.found_files_frame = ff_frame = QGroupBox("recursive search")
        ff_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.found_files_vbox_layout = QVBoxLayout(ff_frame)
        self.found_files_vbox_layout.setSpacing(0)
        self.found_files_vbox_layout.setContentsMargins(0, 0, 0, 0)
        self.found_files_list = QListWidget(ff_frame)
        self.found_files_list.setSizePolicy(QSizePolicy.Expanding,
                                            QSizePolicy.Expanding)
        self.found_files_list.setFrameStyle(QFrame.StyledPanel)
        self.found_files_list.itemActivated.connect(self.on_itemActivated)
        self.found_files_list.setStyleSheet("QListWidget {"
                                            "background-color:transparent;"
                                            "}"
                                            "QListWidget::item {"
                                            "background-color:transparent;"
                                            "}"
                                            "QListWidget::item:selected {"
                                            "background-color: darkgray;"
                                            "}")
        self.found_files_vbox_layout.addWidget(self.found_files_list)
        ff_frame.setCheckable(True)
        ff_frame.setChecked(False)
        ff_frame.setFlat(True)
        self.found_files_list.setVisible(False)
        return self.found_files_frame

    def keyPressEvent(self, event):
        '''
        Enable the shortcats for search and replace
        '''
        self.parent().keyPressEvent(event)

    def on_search(self):
        '''
        Initiate the new search or request a next search result.
        '''
        if self.current_search_text != self.search_field.text(
        ) or self._search_recursive != self.found_files_frame.isChecked():
            # clear current search results
            self._reset()
            self.current_search_text = self.search_field.text()
            if self.current_search_text:
                path_text = {}
                self._wait_for_result = True
                for i in range(self._tabwidget.count()):
                    path_text[self._tabwidget.widget(
                        i).filename] = self._tabwidget.widget(
                            i).document().toPlainText()
                self._search_recursive = self.found_files_frame.isChecked()
                self._search_thread = TextSearchThread(
                    self.current_search_text,
                    self._tabwidget.currentWidget().filename,
                    path_text=path_text,
                    recursive=self._search_recursive)
                self._search_thread.search_result_signal.connect(
                    self.on_search_result)
                self._search_thread.warning_signal.connect(
                    self.on_warning_result)
                self._search_thread.start()
        elif self.search_results:
            self._check_position()
            if self.search_results:
                if self._search_result_index + 1 >= len(self.search_results):
                    self._search_result_index = -1
                self._search_result_index += 1
                self.search_result_signal.emit(
                    *self.search_results[self._search_result_index])
                self.replace_button.setEnabled(True)
        self._update_label()

    def on_search_back(self):
        '''
        Slot to handle the search back function.
        '''
        self._check_position(False)
        if self.search_results:
            self._search_result_index -= 1
            if self._search_result_index < 0:
                self._search_result_index = len(self.search_results) - 1
            self._update_label()
            self.search_result_signal.emit(
                *self.search_results[self._search_result_index])
            self.replace_button.setEnabled(True)

    def _check_position(self, forward=True):
        try:
            # if the position of the textCursor was changed by the user, move the search index
            cur_pos = self._tabwidget.currentWidget().textCursor().position()
            st, _f, pa, idx = self.search_results[self._search_result_index]
            sear_pos = idx + len(st)
            if cur_pos != sear_pos:
                first_idx = self._get_current_index_for_current_file()
                if first_idx != -1:
                    st, _f, pa, idx = self.search_results[first_idx]
                    sear_pos = idx + len(st)
                    while cur_pos > sear_pos and self._tabwidget.currentWidget(
                    ).filename == pa:
                        first_idx += 1
                        st, _f, pa, idx = self.search_results[first_idx]
                        sear_pos = idx + len(st)
                    self._search_result_index = first_idx
                    if forward:
                        self._search_result_index -= 1
                else:
                    self._reset(True)
        except:
            pass

    def _get_current_index_for_current_file(self):
        for index in range(len(self.search_results)):
            _st, _f, pa, _idx = self.search_results[index]
            if self._tabwidget.currentWidget().filename == pa:
                return index
        return -1

    def on_search_result(self, search_text, found, path, index):
        '''
        Slot to handle the signals for search result. This signals are forwarded used
        search_result_signal.
        '''
        if found and search_text == self.current_search_text:
            self.search_results_fileset.add(path)
            item = (search_text, found, path, index)
            if item not in self.search_results:
                self.search_results.append((search_text, found, path, index))
            if self._wait_for_result:
                self._search_result_index += 1
                if index >= self._tabwidget.currentWidget().textCursor(
                ).position() or self._tabwidget.currentWidget(
                ).filename != path:
                    self._wait_for_result = False
                    self.search_result_signal.emit(
                        *self.search_results[self._search_result_index])
                    self.replace_button.setEnabled(True)
        if self.search_results:
            if len(self.search_results_fileset) > 1:
                for item in self.search_results_fileset:
                    pkg, path = package_name(os.path.dirname(item))
                    itemstr = '%s [%s]' % (os.path.basename(item), pkg)
                    if not self.found_files_list.findItems(
                            itemstr, Qt.MatchExactly):
                        list_item = QListWidgetItem(itemstr)
                        list_item.setToolTip(item)
                        self.found_files_list.addItem(list_item)
                        self.found_files_frame.setVisible(True)
                        self.found_files_list.setVisible(
                            len(self.search_results_fileset) > 0)
        self._update_label()

    def on_warning_result(self, text):
        rospy.logwarn(text)

    def on_replace_click(self):
        self.on_replace()
        self.on_search()

    def on_replace(self):
        '''
        Emits the replace signal, but only if currently selected text is equal to the searched one.
        '''
        if self.search_results:
            try:
                search_text, _found, path, index = self.search_results[
                    self._search_result_index]
                cursor = self._tabwidget.currentWidget().textCursor()
                if cursor.selectedText() == search_text:
                    rptxt = self.replace_field.text()
                    for rindex in range(self._search_result_index + 1,
                                        len(self.search_results)):
                        st, _f, pa, idx = self.search_results[rindex]
                        if path == pa:
                            self.search_results.pop(rindex)
                            self.search_results.insert(
                                rindex,
                                (st, _f, pa, idx + len(rptxt) - len(st)))
                        else:
                            break
                    self._remove_search_result(self._search_result_index)
                    self.replace_signal.emit(search_text, path, index, rptxt)
                else:
                    self.replace_button.setEnabled(False)
            except:
                import traceback
                print traceback.format_exc()
                pass

    def on_itemActivated(self, item):
        '''
        Go to the results for the selected file entry in the list.
        '''
        item_path = item.toolTip()
        new_search_index = -1
        tmp_index = -1
        search_index = -1
        tmp_search_text = ''
        for search_text, found, path, index in self.search_results:
            new_search_index += 1
            if item_path == path:
                if tmp_index == -1:
                    tmp_index = new_search_index
                    tmp_search_text = search_text
                    search_index = index
                if new_search_index > self._search_result_index:
                    self.search_result_signal.emit(search_text, found, path,
                                                   index)
                    self._search_result_index = new_search_index
                    self._update_label()
                    return
        if tmp_index != -1:
            self.search_result_signal.emit(tmp_search_text, True, item_path,
                                           search_index)
            self._search_result_index = tmp_index
            self._update_label()

    def on_search_text_changed(self, _text):
        '''
        Clear search result if the text was changed.
        '''
        self._reset()

    def _update_label(self, clear_label=False):
        '''
        Updates the status label for search results. The info is created from search result lists.
        '''
        msg = ' '
        if self.search_results:
            count_files = len(self.search_results_fileset)
            msg = '%d/%d' % (self._search_result_index + 1,
                             len(self.search_results))
            if count_files > 1:
                msg = '%s(%d)' % (msg, count_files)
        if self._search_thread is not None and self._search_thread.is_alive():
            msg = 'searching..%s' % msg
        elif not msg.strip() and self.current_search_text:
            msg = '0 found'
            self.current_search_text = ''
        if clear_label:
            msg = ' '
        self.search_result_label.setText(msg)
        self.find_button_back.setEnabled(len(self.search_results))

    def file_changed(self, path):
        '''
        Clears search results if for changed file are some search results are available
        :param path: changed file path
        :type path: str
        '''
        if path in self.search_results_fileset:
            self._reset()

    def set_replace_visible(self, value):
        self.rplc_frame.setVisible(value)
        self.raise_()
        self.activateWindow()
        if value:
            self.replace_field.setFocus()
            self.replace_field.selectAll()
            self.setWindowTitle("Find / Replace")
        else:
            self.setWindowTitle("Find")
            self.search_field.setFocus()

    def is_replace_visible(self):
        return self.rplc_frame.isVisible()

    def _reset(self, force_new_search=False):
        # clear current search results
        if self._search_thread is not None:
            self._search_thread.search_result_signal.disconnect()
            self._search_thread.stop()
            self._search_thread = None
        self.current_search_text = ''
        self.search_results = []
        self.search_results_fileset = set()
        self.found_files_list.clear()
        self.found_files_list.setVisible(False)
        self._update_label(True)
        self._search_result_index = -1
        self.find_button_back.setEnabled(False)
        if force_new_search:
            self.on_search()

    def enable(self):
        self.setVisible(True)
        #        self.show()
        self.raise_()
        self.activateWindow()
        self.search_field.setFocus()
        self.search_field.selectAll()

    def _remove_search_result(self, index):
        try:
            self.search_results.pop(index)
            # create new set with files contain the search text
            new_path_set = set(path
                               for _st, _fd, path, _idx in self.search_results)
            # remove the file from the list widget
            for pp in self.search_results_fileset - new_path_set:
                for wi_idx in range(self.found_files_list.count()):
                    # we have to compare each tooltip of the item
                    if pp == self.found_files_list.item(wi_idx).toolTip():
                        self.found_files_list.takeItem(wi_idx)
                        break
            self.search_results_fileset = new_path_set
            self.found_files_list.setVisible(
                len(self.search_results_fileset) > 0)
        except:
            import traceback
            print traceback.format_exc()
class SimpleGUI(Plugin):

    # For sending speech
    sound_sig = Signal(SoundRequest)

    # Joints for arm poses
    joint_sig = Signal(JointState)

    def __init__(self, context):
        self.prompt_width = 170
        self.input_width = 250

        super(SimpleGUI, self).__init__(context)
        self.setObjectName('SimpleGUI')
        self._widget = QWidget()

        self._sound_client = SoundClient()

        #find relative path for files to load
        self.local_dir = os.path.dirname(__file__)
        self.dir = os.path.join(self.local_dir, './lib/rqt_simplegui/')
        if not os.path.isdir(self.dir):
            os.makedirs(self.dir)

        #need to add any additional subfolders as needed
        if not os.path.isdir(self.dir + 'animations/'):
            os.makedirs(self.dir + 'animations/')

        # Creates a subscriber to the ROS topic, having msg type SoundRequest
        rospy.Subscriber('robotsound', SoundRequest, self.sound_cb)

        QtGui.QToolTip.setFont(QtGui.QFont('SansSerif', 10))
        self.sound_sig.connect(self.sound_sig_cb)

        # Code used for saving/ loading arm poses for the robot
        switch_srv_name = 'pr2_controller_manager/switch_controller'
        rospy.loginfo('Waiting for switch controller service...')
        rospy.wait_for_service(switch_srv_name)
        self.switch_service_client = rospy.ServiceProxy(
            switch_srv_name, SwitchController)

        self.r_joint_names = [
            'r_shoulder_pan_joint', 'r_shoulder_lift_joint',
            'r_upper_arm_roll_joint', 'r_elbow_flex_joint',
            'r_forearm_roll_joint', 'r_wrist_flex_joint', 'r_wrist_roll_joint'
        ]

        self.l_joint_names = [
            'l_shoulder_pan_joint', 'l_shoulder_lift_joint',
            'l_upper_arm_roll_joint', 'l_elbow_flex_joint',
            'l_forearm_roll_joint', 'l_wrist_flex_joint', 'l_wrist_roll_joint'
        ]

        self.all_joint_names = []
        self.all_joint_poses = []

        # Hash tables storing the name of the pose and the
        # associated positions for that pose, initially empty
        self.saved_l_poses = {}
        self.saved_r_poses = {}

        # Hash tables for storing name of animations and the associated pose list
        self.saved_animations = {}

        self.lock = threading.Lock()
        rospy.Subscriber('joint_states', JointState, self.joint_states_cb)

        #parsing for animations
        dir = os.path.dirname(__file__)
        qWarning(dir)
        filename = os.path.join(self.dir, 'animations/')

        ani_path = filename
        ani_listing = os.listdir(ani_path)
        for infile in ani_listing:
            pose_left = []
            pose_right = []
            left_gripper_states = []
            right_gripper_states = []
            line_num = 1
            for line in fileinput.input(ani_path + infile):
                if (line_num % 2 == 1):
                    pose = [float(x) for x in line.split()]
                    pose_left.append(pose[:len(pose) / 2])
                    pose_right.append(pose[len(pose) / 2:])
                else:
                    states = line.split()
                    left_gripper_states.append(states[0])
                    right_gripper_states.append(states[1])
                line_num += 1
            self.saved_animations[os.path.splitext(infile)[0]] = Quad(
                pose_left, pose_right, left_gripper_states,
                right_gripper_states)

        # Create a trajectory action client
        r_traj_controller_name = '/r_arm_controller/joint_trajectory_action'
        self.r_traj_action_client = SimpleActionClient(r_traj_controller_name,
                                                       JointTrajectoryAction)
        rospy.loginfo(
            'Waiting for a response from the trajectory action server for RIGHT arm...'
        )
        self.r_traj_action_client.wait_for_server()

        l_traj_controller_name = '/l_arm_controller/joint_trajectory_action'
        self.l_traj_action_client = SimpleActionClient(l_traj_controller_name,
                                                       JointTrajectoryAction)
        rospy.loginfo(
            'Waiting for a response from the trajectory action server for LEFT arm...'
        )
        self.l_traj_action_client.wait_for_server()

        # Navigation functionality initialization
        self.roomNav = RoomNavigator()

        self._tf_listener = TransformListener()
        self.animPlay = AnimationPlayer(None, None, None, None)

        # Detection and pickup functionality
        self.pap = PickAndPlaceManager(self._tf_listener, self.roomNav,
                                       self.animPlay)

        QtGui.QToolTip.setFont(QtGui.QFont('SansSerif', 10))
        self.joint_sig.connect(self.joint_sig_cb)

        # Create a large vertical box that is top aligned
        large_box = QtGui.QVBoxLayout()
        large_box.setAlignment(QtCore.Qt.AlignTop)
        large_box.setMargin(0)
        large_box.addItem(QtGui.QSpacerItem(10, 0))

        # Buttons for controlling the head of the robot
        head_box = QtGui.QHBoxLayout()
        head_box.addItem(QtGui.QSpacerItem(230, 0))
        head_box.addWidget(self.create_pressed_button('Head Up'))
        head_box.addStretch(1)
        large_box.addLayout(head_box)

        button_box = QtGui.QHBoxLayout()
        button_box.addItem(QtGui.QSpacerItem(80, 0))
        button_box.addWidget(self.create_pressed_button('Head Turn Left'))
        button_box.addWidget(self.create_pressed_button('Head Down'))
        button_box.addWidget(self.create_pressed_button('Head Turn Right'))
        button_box.addStretch(1)
        button_box.setMargin(0)
        button_box.setSpacing(0)
        large_box.addLayout(button_box)

        # Shows what the robot says
        speech_box = QtGui.QHBoxLayout()

        self.speech_label = QtGui.QLabel('Robot has not spoken yet')
        palette = QtGui.QPalette()
        palette.setColor(QtGui.QPalette.Foreground, QtCore.Qt.blue)
        self.speech_label.setPalette(palette)  #
        speech_box.addItem(QtGui.QSpacerItem(100, 0))
        #speech_box.addWidget(self.speech_label) #

        large_box.addLayout(speech_box)

        # Speak button
        speak_button_box = QtGui.QHBoxLayout()
        speech_prompt = QtGui.QLabel('Enter Speech Text:')
        speech_prompt.setFixedWidth(self.prompt_width)
        speak_button_box.addWidget(speech_prompt)
        robot_says = QtGui.QLineEdit(self._widget)
        robot_says.setFixedWidth(self.input_width)
        robot_says.textChanged[str].connect(self.onChanged)  #
        speak_button_box.addWidget(robot_says)
        speak_button_box.addWidget(self.create_button('Speak'))
        speak_button_box.addStretch(1)
        large_box.addLayout(speak_button_box)

        large_box.addItem(QtGui.QSpacerItem(0, 50))

        # Buttons for arm poses
        pose_button_box1 = QtGui.QHBoxLayout()
        pose_button_box1.addItem(QtGui.QSpacerItem(150, 0))
        pose_button_box1.addWidget(self.create_button('Relax Left Arm'))
        pose_button_box1.addWidget(self.create_button('Relax Right Arm'))
        pose_button_box1.addStretch(1)
        large_box.addLayout(pose_button_box1)

        # Buttons for grippers
        gripper_button_box = QtGui.QHBoxLayout()
        gripper_button_box.addItem(QtGui.QSpacerItem(150, 0))
        gripper_button_box.addWidget(self.create_button('Open Left Gripper'))
        gripper_button_box.addWidget(self.create_button('Open Right Gripper'))
        gripper_button_box.addStretch(1)
        large_box.addLayout(gripper_button_box)

        large_box.addItem(QtGui.QSpacerItem(0, 25))

        # Buttons for animation
        animation_box = QtGui.QHBoxLayout()
        play_anim_label = QtGui.QLabel('Select Animation:')
        play_anim_label.setFixedWidth(self.prompt_width)
        animation_box.addWidget(play_anim_label)
        self.saved_animations_list = QtGui.QComboBox(self._widget)
        animation_box.addWidget(self.saved_animations_list)

        pose_time_label = QtGui.QLabel('Duration(sec):')
        pose_time_label.setFixedWidth(100)
        animation_box.addWidget(pose_time_label)
        self.pose_time = QtGui.QLineEdit(self._widget)
        self.pose_time.setFixedWidth(50)
        self.pose_time.setText('2.0')
        animation_box.addWidget(self.pose_time)

        animation_box.addWidget(self.create_button('Play Animation'))
        animation_box.addStretch(1)
        large_box.addLayout(animation_box)

        animation_box2 = QtGui.QHBoxLayout()
        animation_name_label = QtGui.QLabel('Enter Animation Name:')
        animation_name_label.setFixedWidth(self.prompt_width)
        animation_box2.addWidget(animation_name_label)
        self.animation_name = QtGui.QLineEdit(self._widget)
        self.animation_name.setFixedWidth(self.input_width)
        animation_box2.addWidget(self.animation_name)
        animation_box2.addWidget(self.create_button('Save Animation'))
        animation_box2.addStretch(1)
        large_box.addLayout(animation_box2)

        animation_box3 = QtGui.QHBoxLayout()
        pose_name_label = QtGui.QLabel('Enter Pose Name:')
        pose_name_label.setFixedWidth(self.prompt_width)
        animation_box3.addWidget(pose_name_label)
        self.pose_name_temp = QtGui.QLineEdit(self._widget)
        self.pose_name_temp.setFixedWidth(self.input_width)
        animation_box3.addWidget(self.pose_name_temp)
        animation_box3.addWidget(self.create_button('Add Current Pose'))
        animation_box3.addStretch(1)
        large_box.addLayout(animation_box3)

        # Playing around with UI stuff
        play_box = QtGui.QHBoxLayout()
        pose_sequence_label = QtGui.QLabel('Current Pose Sequence:')
        pose_sequence_label.setFixedWidth(self.prompt_width)
        pose_sequence_label.setAlignment(QtCore.Qt.AlignTop)

        self.list_widget = QListWidget()
        self.list_widget.setDragDropMode(QAbstractItemView.InternalMove)
        self.list_widget.setMaximumSize(self.input_width, 200)
        play_box.addWidget(pose_sequence_label)
        play_box.addWidget(self.list_widget)

        play_box.addStretch(1)
        large_box.addLayout(play_box)

        large_box.addItem(QtGui.QSpacerItem(0, 50))

        # Buttons for first row of base controls
        first_base_button_box = QtGui.QHBoxLayout()
        first_base_button_box.addItem(QtGui.QSpacerItem(70, 0))
        first_base_button_box.addWidget(
            self.create_pressed_button('Rotate Left'))
        first_base_button_box.addWidget(self.create_pressed_button('^'))
        first_base_button_box.addWidget(
            self.create_pressed_button('Rotate Right'))
        first_base_button_box.addStretch(1)
        large_box.addLayout(first_base_button_box)

        # Buttons for second row of base controls
        second_base_button_box = QtGui.QHBoxLayout()
        second_base_button_box.addItem(QtGui.QSpacerItem(70, 0))
        second_base_button_box.addWidget(self.create_pressed_button('<'))
        second_base_button_box.addWidget(self.create_pressed_button('v'))
        second_base_button_box.addWidget(self.create_pressed_button('>'))
        second_base_button_box.addWidget(self.create_button('Move to Bin'))
        second_base_button_box.addWidget(self.create_button('Object Detect'))
        second_base_button_box.addWidget(self.create_button('Clean Room'))
        second_base_button_box.addStretch(1)
        large_box.addLayout(second_base_button_box)

        # Animation related items to store intermediate pose co-ordinates to save
        self.animation_map = {}

        self.create_state = False

        self._widget.setObjectName('SimpleGUI')
        self._widget.setLayout(large_box)
        context.add_widget(self._widget)

        # Look straight and down when launched
        self.head_x = 1.0
        self.head_y = 0.0
        self.head_z = 0.5
        self.head_action(self.head_x, self.head_y, self.head_z)

        # Set grippers to closed on initialization
        self.left_gripper_state = ''
        self.right_gripper_state = ''
        self.gripper_action('l', 0.0)
        self.gripper_action('r', 0.0)

        # Lab 6
        self.marker_publisher = rospy.Publisher('visualization_marker', Marker)

        # Saved states for poses
        saved_pose_box = QtGui.QHBoxLayout()
        self.saved_left_poses = QtGui.QLabel('')
        self.saved_right_poses = QtGui.QLabel('')

        saved_pose_box.addWidget(self.saved_left_poses)
        saved_pose_box.addWidget(self.saved_right_poses)
        large_box.addLayout(saved_pose_box)

        # Preload the map of animations
        self.saved_animations_list.addItems(self.saved_animations.keys())

        # Move the torso all the way down
        # self.torso_down(True)

        # Autonomous navigation stuff
        '''
        self.locations = [Pose(Point(2.48293590546, 3.90075874329, 0.000), Quaternion(0.000, 0.000, -0.783917630973, 0.620864838632)),
                         Pose(Point(3.70106744766, 0.304672241211, 0.000), Quaternion(0.000, 0.000, 0.950186880196, -0.311680754463)),
                         Pose(Point(2.57326722145, 1.51304531097, 0.000), Quaternion(0.000, 0.000, 0.96127194482, -0.275601611212)),
                         Pose(Point(1.28060531616, 1.52380752563, 0.000), Quaternion(0.000, 0.000, 0.946345258806, -0.323157316388)),
                         Pose(Point(2.11048603058, 0.420155525208, 0.000), Quaternion(0.000, 0.000, 0.945222393391, -0.326427062346)),
                         Pose(Point(2.82733058929, -0.739856719971, 0.000), Quaternion(0.000, 0.000, 0.945473998362, -0.325697587373)),
                         Pose(Point(1.29184818268, -1.90485572815, 0.000), Quaternion(0.000, 0.000, 0.942275557345, -0.334838429739)),
                         Pose(Point(0.722846984863, -1.0921459198, 0.000), Quaternion(0.000, 0.000, 0.949330143731, -0.314280572424))]
        '''
        self.locations = [
            Pose(Point(2.04748392105, 2.04748010635, 0.000),
                 Quaternion(0.000, 0.000, -0.776968030817, 0.629540053601)),
            Pose(Point(2.34193611145, 1.43208932877, 0),
                 Quaternion(0, 0, -0.841674385779, 0.539985396398)),
            Pose(Point(3.43202018738, -0.258297920227, 0.000),
                 Quaternion(0.000, 0.000, 0.996656413122, -0.0817067572629)),
            Pose(Point(0.931655406952, -1.96435832977, 0.000),
                 Quaternion(0.000, 0.000, 0.691187586713, 0.722675390458)),
            Pose(Point(-0.369112968445, 0.0330476760864, 0.000),
                 Quaternion(0.000, 0.000, 0.0275340398899, 0.999620866453))
        ]

        self.index = 1

        rospy.loginfo("Completed GUI initialization")

    # Event for when text box is changed
    def onChanged(self, text):
        self.speech_label.setText(text)
        self.speech_label.adjustSize()

    def sound_cb(self, sound_request):
        qWarning('Received sound.')
        self.sound_sig.emit(sound_request)

    def create_button(self, name):
        btn = QtGui.QPushButton(name, self._widget)
        btn.setFixedWidth(150)
        btn.clicked.connect(self.command_cb)
        return btn

    def create_pressed_button(self, name):
        btn = QtGui.QPushButton(name, self._widget)
        btn.setFixedWidth(150)
        btn.pressed.connect(self.command_cb)
        btn.setAutoRepeat(True)  # To make sure the movement repeats itself
        return btn

    def sound_sig_cb(self, sound_request):
        qWarning('Received sound signal.')
        qWarning('Robot said: ' + sound_request.arg)
        self.speech_label.setText(sound_request.arg)  #'Robot said: ' +

#a button was clicked

    def command_cb(self):
        button_name = self._widget.sender().text()

        #robot talk button clicked
        if (button_name == 'Speak'):
            qWarning('Robot will say: ' + self.speech_label.text())
            self._sound_client.say(self.speech_label.text())
            self.show_text_in_rviz("Robot is Speaking")

        #gripper button selected
        elif ('Gripper' in button_name):
            self.gripper_click(button_name)

        # Move forward
        elif (button_name == '^'):
            self.base_action(0.25, 0.0, 0.0, 0.0, 0.0, 0.0)

        # Move left
        elif (button_name == '<'):
            self.base_action(0.0, 0.25, 0.0, 0.0, 0.0, 0.0)

        # Move right
        elif (button_name == '>'):
            self.base_action(0.0, -0.25, 0.0, 0.0, 0.0, 0.0)

        # Move back
        elif (button_name == 'v'):
            self.base_action(-0.25, 0.0, 0.0, 0.0, 0.0, 0.0)

        #Rotate Left
        elif (button_name == 'Rotate Left'):
            self.base_action(0.0, 0.0, 0.0, 0.0, 0.0, 0.50)

        # Rotate Right
        elif (button_name == 'Rotate Right'):
            self.base_action(0.0, 0.0, 0.0, 0.0, 0.0, -0.50)

        # A head button selected
        elif ('Head' in button_name):
            self.rotate_head(button_name)

        #An arm button selected
        #third param unused in freeze/relax
        #Second word in button should be side
        elif ('Arm' in button_name):

            arm_side = button_name.split()[1]

            if ('Freeze' in button_name or 'Relax' in button_name):
                new_arm_state = button_name.split()[0]
                self.toggle_arm(arm_side[0].lower(), new_arm_state, True)

                old_arm_state = ''
                if (new_arm_state == 'Relax'):
                    old_arm_state = 'Freeze'
                else:
                    old_arm_state = 'Relax'

                self._widget.sender().setText('%s %s Arm' %
                                              (old_arm_state, arm_side))

        elif ('Play Animation' == button_name):
            self.animPlay.left_poses = self.saved_animations[
                self.saved_animations_list.currentText()].left
            self.animPlay.right_poses = self.saved_animations[
                self.saved_animations_list.currentText()].right
            self.animPlay.left_gripper_states = self.saved_animations[
                self.saved_animations_list.currentText()].left_gripper
            self.animPlay.right_gripper_states = self.saved_animations[
                self.saved_animations_list.currentText()].right_gripper
            if self.pose_time.text() == '':
                self.show_warning('Please enter a duration in seconds.')
            else:
                self.animPlay.play(self.pose_time.text())

        elif ('Animation' in button_name):
            if ('Save' in button_name):
                if self.animation_name.text() == '':
                    self.show_warning('Please enter name for animation')
                else:
                    self.save_animation(self.animation_name.text())
                    self.list_widget.clear()
                    self.animation_name.setText('')

        elif ('Add Current Pose' == button_name):
            if self.pose_name_temp.text() == '':
                self.show_warning('Insert name for pose')
            else:
                self.animation_map[self.pose_name_temp.text()] = Quad(
                    self.get_joint_state('l'), self.get_joint_state('r'),
                    self.left_gripper_state, self.right_gripper_state)
                list_item = QListWidgetItem()
                list_item.setText(self.pose_name_temp.text())
                self.list_widget.addItem(list_item)
                self.pose_name_temp.setText('')

        elif ('Move to Bin' == button_name):
            self.move_to_bin_action()
        elif ('Clean Room' == button_name):
            rospy.loginfo("STARTING AUTONOMOUS MODE")
            self.tuck_arms()

            while (self.index < len(self.locations)):
                self.roomNav.move_to_trash_location(self.locations[self.index])
                # self.index += 1

                self.head_action(1.0, 0, -0.50, True)
                # Returns Nonce if nothing, and the point of the first object it sees otherwise
                map_point = self.pap.detect_objects()

                if (map_point == None):
                    self.index += 1
                else:
                    self.pick_and_move_trash_action()

            rospy.loginfo("FINISHED AUTONOMOUS MODE")
            self.index = 1

        elif ('Object Detect' == button_name):
            self.pick_and_move_trash_action()

    def pick_and_move_trash_action(self, map_point=None):
        if map_point == None:
            self.head_action(1.0, 0, -0.50, True)
            map_point = self.pap.detect_objects()

        if map_point == None:
            return

        # Convert to base link and move towards the object 0.50m away
        map_point = Transformer.transform(self._tf_listener, map_point.pose,
                                          map_point.header.frame_id,
                                          '/base_link')

        rospy.loginfo("Object is " + str(map_point.pose.position.x) + " away")
        '''
        if(map_point.pose.position.x < 0.8):
            self.roomNav.move_to_trash_location(self.locations[self.index - 1])
        '''
        move_back_first = False
        if (map_point.pose.position.x < 0.7):
            move_back_first = True

        map_point.pose.position.x -= 0.450
        map_point = Transformer.transform(self._tf_listener, map_point.pose,
                                          '/base_link', '/map')

        if (move_back_first):
            self.roomNav.move_to_trash_location(self.locations[self.index - 1])

        success = self.roomNav.move_to_trash_location(map_point.pose)
        '''This part of the code strafes the robot left to get closer to the object'''
        '''
        rate = rospy.Rate(10)
        position = Point()
        move_cmd = Twist()
        move_cmd.linear.y = 0.25
        odom_frame = '/odom_combined'
        
        # Find out if the robot uses /base_link or /base_footprint
        try:
            self._tf_listener.waitForTransform(odom_frame, '/base_footprint', rospy.Time(), rospy.Duration(1.0))
            self.base_frame = '/base_footprint'
        except (tf.Exception, tf.ConnectivityException, tf.LookupException):
           try:
               self._tf_listener.waitForTransform(odom_frame, '/base_link', rospy.Time(), rospy.Duration(1.0))
               self.base_frame = '/base_link'
           except (tf.Exception, tf.ConnectivityException, tf.LookupException):
               rospy.loginfo("Cannot find transform between " + odom_frame + " and /base_link or /base_footprint")
               rospy.signal_shutdown("tf Exception")
        
            # Get current position
            position = self.get_odom()
            
            x_start = position.x
            y_start = position.y
            
            # Distance travelled
            distance = 0
            goal_distance = 0.25
            rospy.loginfo("Strafing left")
            # Enter the loop to move along a side
            while distance < goal_distance:
                rospy.loginfo("Distance is at " + str(distance))
                # Publish the Twist message and sleep 1 cycle
                self.base_action(0, 0.25, 0, 0, 0, 0)
                rate.sleep()
                
                # Get the current position
                position = self.get_odom()
                
                # Compute the Euclidean distance from the start
                distance = abs(position.y - y_start) 
        '''

        if (success):
            # Move head to look at the object, this will wait for a result
            self.head_action(0, 0.4, 0.55, True)

            # Move arms to ready pickup position, this will wait for a result before trying to detect and pick up object
            self.animPlay.left_poses = self.saved_animations[
                'ready_pickup'].left
            self.animPlay.right_poses = self.saved_animations[
                'ready_pickup'].right
            self.animPlay.left_gripper_states = self.saved_animations[
                'ready_pickup'].left_gripper
            self.animPlay.right_gripper_states = self.saved_animations[
                'ready_pickup'].right_gripper
            self.animPlay.play('3.0')

            for i in range(0, 3):
                success = self.pap.detect_and_pickup()
                # Move head back to look forward
                # Move head to look at the object, this will wait for a result
                self.head_action(1.0, 0.0, 0.55, True)
                if success:
                    break

            # Move to bin
            self.move_to_bin_action()

    def get_odom(self):
        # Get the current transform between the odom and base frames
        try:
            trans = self._tf_listener.lookupTransform('/odom_combined',
                                                      self.base_frame,
                                                      rospy.Time(0))
        except (tf.Exception, tf.ConnectivityException, tf.LookupException):
            rospy.loginfo("TF Exception")
            return

        return Point(trans[0][0], trans[0][1], trans[0][2])

    # gripper_type is either 'l' for left or 'r' for right
    # gripper position is the position as a parameter to the gripper goal
    def gripper_action(self, gripper_type, gripper_position):
        name_space = '/' + gripper_type + '_gripper_controller/gripper_action'

        gripper_client = SimpleActionClient(name_space, GripperCommandAction)
        gripper_client.wait_for_server()
        gripper_goal = GripperCommandGoal()
        gripper_goal.command.position = gripper_position
        gripper_goal.command.max_effort = 30.0
        gripper_client.send_goal(gripper_goal)
        # update the state of the current gripper being modified
        if (gripper_type == 'l'):
            if (gripper_position == 0.0):
                self.left_gripper_state = 'closed'
            else:
                self.left_gripper_state = 'open'
        else:
            if (gripper_position == 0.0):
                self.right_gripper_state = 'closed'
            else:
                self.right_gripper_state = 'open'

    def base_action(self, x, y, z, theta_x, theta_y, theta_z):
        topic_name = '/base_controller/command'
        base_publisher = rospy.Publisher(topic_name, Twist)

        twist_msg = Twist()
        twist_msg.linear = Vector3(x, y, z)
        twist_msg.angular = Vector3(theta_x, theta_y, theta_z)

        base_publisher.publish(twist_msg)

    # Moves the torso of the robot down to its maximum
    def torso_down(self, wait=False):
        self.torso_client = SimpleActionClient(
            '/torso_controller/position_joint_action',
            SingleJointPositionAction)
        torso_goal = SingleJointPositionGoal()
        torso_goal.position = 0.0
        torso_goal.min_duration = rospy.Duration(5.0)
        torso_goal.max_velocity = 1.0
        self.torso_client.send_goal(torso_goal)
        if wait:
            # wait for the head movement to finish before we try to detect and pickup an object
            finished_within_time = self.torso_client.wait_for_result(
                rospy.Duration(15))
            # Check for success or failure
            if not finished_within_time:
                self.torso_client.cancel_goal()
                rospy.loginfo("Timed out achieving torso movement goal")
            else:
                state = self.torso_client.get_state()
                if state == GoalStatus.SUCCEEDED:
                    rospy.loginfo("Torso movement goal succeeded!")
                    rospy.loginfo("State:" + str(state))
                else:
                    rospy.loginfo(
                        "Torso movement goal failed with error code: " +
                        str(state))

    def head_action(self, x, y, z, wait=False):
        name_space = '/head_traj_controller/point_head_action'
        head_client = SimpleActionClient(name_space, PointHeadAction)
        head_goal = PointHeadGoal()
        head_goal.target.header.frame_id = 'base_link'
        head_goal.min_duration = rospy.Duration(1.0)
        head_goal.target.point = Point(x, y, z)
        head_client.send_goal(head_goal)
        if wait:
            # wait for the head movement to finish before we try to detect and pickup an object
            finished_within_time = head_client.wait_for_result(
                rospy.Duration(5))
            # Check for success or failure
            if not finished_within_time:
                head_client.cancel_goal()
                rospy.loginfo("Timed out achieving head movement goal")
            else:
                state = head_client.get_state()
                if state == GoalStatus.SUCCEEDED:
                    rospy.loginfo("Head movement goal succeeded!")
                    rospy.loginfo("State:" + str(state))
                else:
                    rospy.loginfo(
                        "Head movement goal failed with error code: " +
                        str(self.goal_states[state]))

    def tuck_arms(self):
        rospy.loginfo('Left tuck arms')
        self.animPlay.left_poses = self.saved_animations['left_tuck'].left
        self.animPlay.right_poses = self.saved_animations['left_tuck'].right
        self.animPlay.left_gripper_states = self.saved_animations[
            'left_tuck'].left_gripper
        self.animPlay.right_gripper_states = self.saved_animations[
            'left_tuck'].right_gripper
        self.animPlay.play('3.0')

    def move_to_bin_action(self):
        # First tuck arms
        self.tuck_arms()

        # Move to the bin
        rospy.loginfo('Clicked the move to bin button')
        self.roomNav.move_to_bin()
        # Throw the trash away
        rospy.loginfo('Throwing trash away with left arm')
        self.animPlay.left_poses = self.saved_animations['l_dispose'].left
        self.animPlay.right_poses = self.saved_animations['l_dispose'].right
        self.animPlay.left_gripper_states = self.saved_animations[
            'l_dispose'].left_gripper
        self.animPlay.right_gripper_states = self.saved_animations[
            'l_dispose'].right_gripper
        self.animPlay.play('2.0')
        # Tuck arms again
        self.tuck_arms()

    def shutdown_plugin(self):
        # TODO unregister all publishers here
        pass

    def save_settings(self, plugin_settings, instance_settings):
        # TODO save intrinsic configuration, usually using:
        # instance_settings.set_value(k, v)
        pass

    def restore_settings(self, plugin_settings, instance_settings):
        # TODO restore intrinsic configuration, usually using:
        # v = instance_settings.value(k)
        pass

    def show_text_in_rviz(self, text):
        marker = Marker(type=Marker.TEXT_VIEW_FACING,
                        id=0,
                        lifetime=rospy.Duration(1.5),
                        pose=Pose(Point(0.5, 0.5, 1.45),
                                  Quaternion(0, 0, 0, 1)),
                        scale=Vector3(0.06, 0.06, 0.06),
                        header=Header(frame_id='base_link'),
                        color=ColorRGBA(0.0, 1.0, 0.0, 0.8),
                        text=text)
        self.marker_publisher.publish(marker)

    def show_arrow_in_rviz(self, arrow):
        marker = Marker(type=Marker.ARROW,
                        id=0,
                        lifetime=rospy.Duration(1.5),
                        pose=Pose(Point(0.5, 0.5, 1.45),
                                  Quaternion(0, 0, 0, 1)),
                        scale=Vector3(0.06, 0.06, 0.06),
                        header=Header(frame_id='base_link'),
                        color=ColorRGBA(0.0, 1.0, 0.0, 0.8),
                        arrow=arrow)
        self.marker_publisher.publish(marker)

    def save_animation(self, animation_name):
        if animation_name != '':
            filename = os.path.join(self.dir, 'animations/')
            anim_file = open(filename + animation_name + '.txt', 'w')
            l_animation_queue = []
            r_animation_queue = []
            l_gripper_queue = []
            r_gripper_queue = []
            for i in range(self.list_widget.count()):
                item = self.list_widget.item(i)
                pose_name = item.text()
                anim_file.write(
                    re.sub(
                        ',', '',
                        str(self.animation_map[pose_name].left).strip('[]') +
                        ' ' +
                        str(self.animation_map[pose_name].right).strip('[]')))
                anim_file.write('\n')
                anim_file.write(
                    str(self.animation_map[pose_name].left_gripper) + ' ' +
                    str(self.animation_map[pose_name].right_gripper))
                l_animation_queue.append(self.animation_map[pose_name].left)
                r_animation_queue.append(self.animation_map[pose_name].right)
                l_gripper_queue.append(
                    self.animation_map[pose_name].left_gripper)
                r_gripper_queue.append(
                    self.animation_map[pose_name].right_gripper)
                anim_file.write('\n')
            anim_file.close()

            self.saved_animations[animation_name] = Quad(
                l_animation_queue, r_animation_queue, l_gripper_queue,
                r_gripper_queue)
            self.saved_animations_list.addItem(
                animation_name)  # Bug? Multiple entries

            # Reset the pending queue
            self.l_animation_queue = []
            self.r_animation_queue = []
        else:
            self.show_warning('Please insert name for animation')

    def gripper_click(self, button_name):
        grip_side = ''
        grip_side_text = ''

        if ('Left' in button_name):
            grip_side = 'l'
            grip_side_text = 'left'
        else:
            grip_side = 'r'
            grip_side_text = 'right'

        if ('Open' in button_name):
            grip_action = 20.0
            grip_action_text = 'close'
            qWarning('Robot opened %s gripper' % (grip_side_text))
        else:
            grip_action = 0.0
            grip_action_text = 'open'
            qWarning('Robot closed %s gripper' % (grip_side_text))

        self.show_text_in_rviz(
            "%sing %s Gripper" %
            (grip_action_text.capitalize(), grip_side_text.capitalize()))
        self.gripper_action(grip_side, grip_action)

        self._widget.sender().setText(
            '%s %s Gripper' %
            (grip_action_text.capitalize(), grip_side_text.capitalize()))

    def rotate_head(self, button_name):
        if ('Left' in button_name):
            #qWarning('x: %s, y: %s' % (self.head_x, self.head_y))

            if (self.head_x < -0.8 and self.head_y > 0.0):
                self.show_warning('Can\'t rotate anymore')

            elif (self.head_y < 0.0):
                self.head_x += 0.1
                self.head_y = -((1.0 - self.head_x**2.0)**0.5)
                self.show_text_in_rviz("Turning Head Left")

            else:
                self.head_x -= 0.1
                self.head_y = (1.0 - self.head_x**2.0)**0.5
                self.show_text_in_rviz("Turning Head Left")

            qWarning('x: %s, y: %s' % (self.head_x, self.head_y))
            self.head_action(self.head_x, self.head_y, self.head_z)

        elif ('Up' in button_name):
            if (self.head_z <= 1.6):
                self.head_z += 0.1
                self.show_text_in_rviz("Moving Head Up")
                self.head_action(self.head_x, self.head_y, self.head_z)
            else:
                self.show_warning('Can\'t look up anymore')

        elif ('Down' in button_name):
            if (self.head_z >= -2.2):
                self.head_z -= 0.1
                self.show_text_in_rviz("Moving Head Down")
                self.head_action(self.head_x, self.head_y, self.head_z)
            else:
                self.show_warning('Can\'t look down anymore')

        else:
            #qWarning('x: %s, y: %s' % (self.head_x, self.head_y))
            if (self.head_x < -0.8 and self.head_y < 0.0):
                self.show_warning('Can\'t rotate anymore')

            elif (self.head_y > 0.0):
                self.head_x += 0.1
                self.head_y = (1.0 - self.head_x**2.0)**0.5
                self.show_text_in_rviz("Turning Head Right")

            else:
                self.head_x -= 0.1
                self.head_y = -((1.0 - self.head_x**2.0)**0.5)
                self.show_text_in_rviz("Turning Head Right")

            #qWarning('x: %s, y: %s' % (self.head_x, self.head_y))
            self.head_action(self.head_x, self.head_y, self.head_z)

    def toggle_arm(self, side, toggle, button):
        controller_name = side + '_arm_controller'

        start_controllers = []
        stop_controllers = []
        if (toggle == 'Relax'):
            stop_controllers.append(controller_name)
        else:
            start_controllers.append(controller_name)
        self.set_arm_mode(start_controllers, stop_controllers)

    def set_arm_mode(self, start_controllers, stop_controllers):
        try:
            self.switch_service_client(start_controllers, stop_controllers, 1)
        except rospy.ServiceException:
            rospy.logerr('Could not change arm mode.')

    def joint_states_cb(self, msg):
        '''Callback function that saves the joint positions when a
            joint_states message is received'''
        self.lock.acquire()
        self.all_joint_names = msg.name
        self.all_joint_poses = msg.position
        self.joint_sig.emit(msg)
        self.lock.release()

    def joint_sig_cb(self, msg):
        pass

    def get_joint_state(self, side_prefix):
        '''Returns position for arm joints on the requested side (r/l)'''
        if side_prefix == 'r':
            joint_names = self.r_joint_names
        else:
            joint_names = self.l_joint_names

        if self.all_joint_names == []:
            rospy.logerr("No robot_state messages received yet!\n")
            return None

        positions = []
        self.lock.acquire()
        for joint_name in joint_names:
            if joint_name in self.all_joint_names:
                index = self.all_joint_names.index(joint_name)
                position = self.all_joint_poses[index]
                positions.append(position)
            else:
                rospy.logerr("Joint %s not found!", joint_name)
                self.lock.release()
                return None

        self.lock.release()
        return positions

    def show_warning(self, text):
        qWarning(text)
        msgBox = QMessageBox()
        msgBox.setText(text)
        msgBox.exec_()