'''
Description: 
Version: 1.0
Autor: Sun Yalun
Date: 2024-09-05 14:53:32
LastEditors: Sun Yalun
LastEditTime: 2024-09-05 15:46:54
'''
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import rospy
import rosbag
import sys
import os
import signal
import subprocess
from geometry_msgs.msg import PoseWithCovarianceStamped, Twist
from move_base_msgs.msg import MoveBaseActionGoal
from datetime import datetime


class RosbagRecorder:
    def __init__(self, bag_dir, count):
        rospy.init_node('rosbag_recorder', anonymous=True)
        rospy.set_param('/use_sim_time', False)
        self.goal_sub = rospy.Subscriber('/move_base/goal', MoveBaseActionGoal, self.goal_callback)
        self.pose_sub = rospy.Subscriber('/amcl_pose', PoseWithCovarianceStamped, self.pose_callback)
        self.cmd_vel_sub = rospy.Subscriber('/cmd_vel', Twist, self.cmd_vel_callback)

        self.goal_position = None
        self.bag_process = None
        self.recording = False
        self.pose_position = None
        self.cmd_vel = None
        self.bag_dir = bag_dir
        self.bag_count = 1
        self.total_count = int(count)

    def goal_callback(self, msg):
        # 如果当前已录制的 bag 文件数量大于等于传入的 count 参数,就不再录制
        if self.bag_count > self.total_count:
            rospy.loginfo("Recording limit reached. Exiting...")
            self.shutdown_node()
            return
        # 更新时间戳为当前时间
        msg.header.stamp = rospy.Time.now()
        self.goal_position = msg.goal.target_pose.pose.position
        rospy.loginfo("Goal received, starting rosbag recording...")

        bag_file_name = f"test-{self.bag_count}.bag"
        bag_file_path = os.path.join(self.bag_dir, bag_file_name)
        self.bag_path = bag_file_path  
        self.start_recording()
    def pose_callback(self, msg):
        # 更新时间戳为当前时间
        msg.header.stamp = rospy.Time.now()
        self.pose_position = msg.pose.pose.position
        self.check_stop_condition()

    def cmd_vel_callback(self, msg):
        # 更新时间戳为当前时间
        # msg.header.stamp = rospy.Time.now()
        self.cmd_vel = msg
        self.check_stop_condition()

    def start_recording(self):
        if not self.recording:
            self.bag_process = subprocess.Popen(['rosbag', 'record', '-O', self.bag_path, '/amcl_pose', '/imu', '/obstacle_detection', '/odom', '/sys_info'], preexec_fn=os.setsid)
            self.recording = True

    def stop_recording(self):
        if self.recording and self.bag_process:
            rospy.loginfo("Stopping rosbag recording...")
            # os.killpg(os.getpgid(self.bag_process.pid), signal.SIGTERM)  # 首先发送SIGTERM信号
            os.killpg(os.getpgid(self.bag_process.pid), signal.SIGINT)  # 首先发送SIGINT信号
            try:
                self.bag_process.wait(timeout=10)  # 等待进程终止,如果超过10秒,进行强制终止
            except subprocess.TimeoutExpired:
                rospy.logwarn("Rosbag process did not terminate, sending SIGKILL...")
                os.killpg(os.getpgid(self.bag_process.pid), signal.SIGKILL)  # 强制终止
                self.bag_process.wait()  # 再次等待确保进程已经被终止                      
            self.recording = False
            self.bag_count += 1

            # 如果录制的包数量达到总数,停止整个节点
            if self.bag_count > self.total_count:
                rospy.loginfo("All recordings completed. Exiting...")
                rospy.sleep(2)  # 等待一秒,确保rosbag_recorder节点已经退出
                self.shutdown_node()

    def check_stop_condition(self):
        if self.goal_position and self.pose_position and self.cmd_vel:
            distance = self.calculate_distance(self.pose_position, self.goal_position)
            if distance < 0.3 and self.cmd_vel.linear.x == 0 and self.cmd_vel.linear.y == 0:
                self.stop_recording()

    def calculate_distance(self, pos1, pos2):
        return ((pos1.x - pos2.x) ** 2 + (pos1.y - pos2.y) ** 2) ** 0.5

    def shutdown_node(self):
        """停止ROS节点和当前进程"""
        rospy.loginfo("Shutting down ROS node and killing the process.")
        rospy.sleep(2)  # 等待2秒,确保rosbag_recorder节点已经退出
        rospy.signal_shutdown("Completed all recordings.")
        sys.exit(0)  # 终止Python脚本

if __name__ == '__main__':
    try:
        bag_folder_path = sys.argv[1]
        count = sys.argv[2]
        recorder = RosbagRecorder(bag_folder_path, count)
        rospy.spin()
    except rospy.ROSInterruptException:
        pass