package main

import (
	"sync"
	"time"

	"github.com/goburrow/serial"

	"lc/common/protocol"
)

var _once sync.Once
var _single *SerialMgr

type SerialMgr struct {
	mu            sync.Mutex
	mapSerial     map[uint8]*serialPort
	mapSerialPort map[uint8]*protocol.SerialPort
}

func GetSerialMgr() *SerialMgr {
	_once.Do(func() {
		_single = &SerialMgr{
			mapSerial:     make(map[uint8]*serialPort),
			mapSerialPort: make(map[uint8]*protocol.SerialPort),
		}
	})
	return _single
}

func openSerialPort(sp *protocol.SerialPort) (*serialPort, error) {
	config := serial.Config{Address: sp.Address, BaudRate: sp.BaudRate, DataBits: int(sp.DataBits),
		StopBits: int(sp.StopBits), Parity: sp.Parity,
		Timeout: time.Duration(sp.Timeout) * time.Microsecond}
	var err error
	var port serialPort
	port.setSerialConfig(config)
	port.SetAutoReconnect(SerialDefaultAutoReconnect)
	err = port.connect()
	if err != nil {
		return nil, err
	}
	return &port, nil
}

func (o *SerialMgr) AddSerialPorts(mapSP map[uint8]*protocol.SerialPort) {
	if len(mapSP) == 0 {
		return
	}
	o.mu.Lock()
	defer o.mu.Unlock()
	//先全部关闭并删除
	for k, v := range o.mapSerial {
		_ = v.Close()
		delete(o.mapSerial, k)
	}
	//重新打开
	for _, sp := range mapSP {
		var s protocol.SerialPort
		s = *sp
		port, _ := openSerialPort(&s)
		if port != nil {
			o.mapSerial[sp.Code] = port
		}
	}
	o.mapSerialPort = mapSP
}

func (o *SerialMgr) UpdateSerialPort(sp *protocol.SerialPort) error {
	if sp == nil {
		return nil
	}
	o.mu.Lock()
	defer o.mu.Unlock()
	if s, ok := o.mapSerial[sp.Code]; ok { //存在则关闭，并重新打开
		_ = s.Close() //关闭

		delete(o.mapSerial, sp.Code)
	}
	port, err := openSerialPort(sp)
	if port != nil {
		o.mapSerial[sp.Code] = port
	}
	o.mapSerialPort[sp.Code] = sp
	return err
}

func (o *SerialMgr) RemoveSerialPort(sp *protocol.SerialPort) error {
	if sp == nil {
		return nil
	}
	var err error
	o.mu.Lock()
	defer o.mu.Unlock()
	if s, ok := o.mapSerial[sp.Code]; ok { //存在则关闭，并重新打开
		err = s.Close() //关闭
		delete(o.mapSerial, sp.Code)
	}
	delete(o.mapSerialPort, sp.Code)
	return err
}

func (o *SerialMgr) GetSerialPort(code uint8) *serialPort {
	o.mu.Lock()
	defer o.mu.Unlock()
	if s, ok := o.mapSerial[code]; ok {
		return s
	}
	if sp, ok := o.mapSerialPort[code]; ok {
		port, _ := openSerialPort(sp)
		if port != nil {
			o.mapSerial[code] = port
			return port
		}
	}
	return nil
}
