import socket
import sys
import time
import serial
import select
from collections import deque

def parse_to_graphite(data, root='rc.bms', timestamp=None):
    if not timestamp:
        timestamp = int(time.time())
    results = []

    lines = data.strip().split('\n')
    for line in lines:
        if line.startswith('BMS'):
            parts = line.split()
            bank_battery = parts[1]
            metric_name = ' '.join(parts[2:-1]).replace(' ', '_')
            metric_value = parts[-1]

            # Remove trailing colon in the metric name if present
            if metric_name.endswith(':'):
                metric_name = metric_name[:-1]

            if 'Cell' in metric_name and 'Voltage' in metric_name and 'Cell' in metric_name.split('_')[0]:
                cell_number = metric_name.split('_')[1]
                metric_name = f"Cell.{cell_number}.Voltage"

            metric_path = f"{root}.{bank_battery}.{metric_name}"
            results.append(f"{metric_path} {metric_value} {timestamp}")
    return results

def send_to_graphite(data, host='10.6.0.1', port=2003):
    try:
        with socket.create_connection((host, port), timeout=1) as sock:
            while data:
                message = data.popleft()
                sock.sendall(message.encode('utf-8'))
    except (socket.error, socket.timeout) as e:
        print(f"Failed to send data, will drop if buffer is full. Error: {e}", file=sys.stderr)

def main():
    if len(sys.argv) < 2:
        print("Usage: python script.py <serial_device>")
        sys.exit(1)

    serial_device = sys.argv[1]
    ser = serial.Serial(serial_device, 115200, timeout=1)
    data_buffer = deque(maxlen=100)  # Buffer up to 100 messages
    print(f"Reading data from {serial_device}, press CTRL+C to quit:")

    try:
        while True:
            if select.select([ser], [], [], 0)[0]:  # Check if there is data to read
                line = ser.readline().decode('utf-8').strip()
                if line:
                    print(f"{line}")  # Output raw line to screen
                    graphite_data = parse_to_graphite(line)
                    for data in graphite_data:
                        if len(data_buffer) < data_buffer.maxlen:
                            data_buffer.append(data + '\n')

            # Try to send data if the buffer is not empty
            if data_buffer:
                send_to_graphite(data_buffer)

    except KeyboardInterrupt:
        print("Exiting...")
    finally:
        ser.close()

if __name__ == '__main__':
    main()
