# -*- coding: utf-8 -*-
"""
Created on Wed Feb 15 10:50:32 2023

@author: dietz
"""

import serial
import time
import numpy as np
import requests
import multiprocessing as mp

def main():
    filepath = "Path"

    # Count lines to preallocate arrays
    with open(filepath, 'r', encoding='UTF-8') as file:
        line_count = sum(1 for _ in file)

    gcode_lines = [None] * line_count
    line_byte_lengths = [None] * line_count
    segment_types = [None] * line_count
    coords = np.ndarray([line_count, 6])  # X, Y, Z, E, F, S

    # Get total file size in bytes
    with open(filepath, 'r', encoding='UTF-8') as file:
        total_byte_count = len(file.read())

    # Parse G-code line by line
    with open(filepath, 'r', encoding='UTF-8') as file:
        for index, line in enumerate(file):
            line_byte_lengths[index] = len(line)
            gcode_lines[index] = line.rstrip()
            tokens = line.split()
            found_flags = np.zeros(6)

            for token in tokens:
                for i, axis in enumerate(["X", "Y", "Z", "E", "F", "S"]):
                    if token.startswith(axis):
                        try:
                            value = float(token[1:])
                            coords[index, i] = value
                            found_flags[i] += 1
                        except:
                            pass

            # Detect segment type if present
            parts = line.split(";TYPE:", 1)
            if len(parts) > 1:
                segment_types[index] = parts[1]
            elif index != 0:
                segment_types[index] = segment_types[index - 1]

            # Inherit previous coordinate values if not updated
            if index != 0:
                for i in range(found_flags.size):
                    if found_flags[i] == 0:
                        coords[index, i] = coords[index - 1, i]

    # Save parsed data
    np.save("Coords.npy", coords[:, :])
    np.save("segment_types.npy", segment_types)
    np.save("line_byte_lengths.npy", line_byte_lengths)
    np.save("total_byte_count.npy", total_byte_count)

    # Connect to printer and start force data collection
    requests.get("http://130.83.89.38/rr_connect")
    q = mp.Queue()
    force_process = mp.Process(target=collect_force_data, args=(q,))
    force_process.start()

    # Upload G-code
    print("Uploading G-code")
    with open(filepath, "rb") as f:
        requests.post("http://130.83.89.38/rr_upload?name=/gcodes/lokalupload.gcode", files={filepath: f})

    # Start print job
    print("Starting G-code execution")
    requests.get("http://130.83.89.38/rr_gcode", params={"gcode": "M23 lokalupload.gcode"})
    requests.get("http://130.83.89.38/rr_gcode", params={"gcode": "M24"})

    # Monitor file position during print
    file_pos_payload = {"key": "job.filePosition", "flag": "f"}
    file_pos_log = []
    timestamp_log = []

    print("Receiving printer data")
    try:
        while True:
            response = requests.get("http://130.83.89.38/rr_model", params=file_pos_payload)
            result_str = response.text.split('"result":')[1].split("}")[0]
            file_position = float(result_str)
            file_pos_log.append(file_position)
            timestamp_log.append(time.time())
            time.sleep(0.1)
            if file_position == 0:
                break
    except:
        time.sleep(1000)

    print("Print job finished or failed")

    # Save data logs
    np.save("file_position_log.npy", file_pos_log)
    np.save("timestamp_log.npy", timestamp_log)

    # Stop force data collection
    q.put("stop")
    force_process.join()
    time.sleep(1000)

def collect_force_data(queue):
    ser = serial.Serial("COM5", 115200, timeout=5)
    force_data = []
    time_stamps = []
    index = 0

    # Wait for valid float data before starting logging
    while True:
        try:
            line = ser.readline().decode("utf-8")
            float(line)
            break
        except:
            continue

    # Start reading force data
    while True:
        if index % 30 == 0 and not queue.empty():
            break

        line = ser.readline().decode("utf-8")
        index += 1
        try:
            force = float(line)
            force_data.append(force)
            time_stamps.append(time.time())
        except:
            continue

        if ser.in_waiting > 10:
            print(f"{ser.in_waiting} bytes in buffer at time: {time.time()}", flush=True)

    ser.close()
    np.save("force_data.npy", force_data)
    np.save("force_timestamps.npy", time_stamps)

if __name__ == '__main__':
    main()
