#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Melsec 模拟设备服务器
提供模拟的 Melsec 设备用于测试在线脚本中的 Melsec 内置函数
"""

import threading
import socket
import struct
import time

print("Melsec 模拟设备服务器")


class MockMelsecServer:
    """模拟 Melsec PLC 服务器用于测试"""
    
    def __init__(self, host='127.0.0.1', port=5007):
        self.host = host
        self.port = port
        self.server_socket = None
        self.running = False
        self.thread = None
        
        # 模拟数据存储 (按照Melsec地址格式)
        self.memory_areas = {
            'M': {  # M 位地址
                100: True,
                101: False,
                102: True,
                103: False,
                200: False,
                201: True
            },
            'D': {  # D 字地址
                100: 1234,
                101: 5678,
                200: 9999,
                300: 42
            },
            'D_STRING': {  # D 字地址存储的字符串
                500: "HELLO",
                502: "WORLD", 
                600: "TEST",
                602: "DATA"
            }
        }
    
    def start(self):
        """启动模拟服务器"""
        try:
            self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.server_socket.bind((self.host, self.port))
            self.server_socket.listen(5)
            self.running = True
            
            self.thread = threading.Thread(target=self._server_loop)
            self.thread.daemon = True
            self.thread.start()
            
            print(f"🟢 模拟 Melsec 服务器已启动：{self.host}:{self.port}")
            print(f"📊 模拟数据:")
            print(f"   - M100=True, M101=False, M102=True, M200=False")
            print(f"   - D100=1234, D101=5678, D200=9999, D300=42")
            print(f"   - D500-501='HELLO', D600-601='TEST'")
            time.sleep(0.1)  # 等待服务器完全启动
            
        except Exception as e:
            print(f"❌ 启动模拟 Melsec 服务器失败: {str(e)}")
            raise
    
    def stop(self):
        """停止模拟服务器"""
        self.running = False
        if self.server_socket:
            self.server_socket.close()
        if self.thread:
            self.thread.join(timeout=1.0)
        print("🔴 模拟 Melsec 服务器已停止")
    
    def _server_loop(self):
        """服务器主循环"""
        while self.running:
            try:
                client_socket, addr = self.server_socket.accept()
                print(f"📞 客户端连接: {addr}")
                
                # 处理客户端请求
                self._handle_client(client_socket)
                
            except Exception as e:
                if self.running:
                    print(f"❌ 服务器循环错误: {str(e)}")
                break
    
    def _handle_client(self, client_socket):
        """处理客户端请求"""
        try:
            # 接收请求
            data = client_socket.recv(1024)
            if not data:
                return
            
            print(f"📨 收到请求数据: {data.hex()}")
            
            # 解析并响应
            response = self._process_melsec_request(data)
            
            if response:
                client_socket.send(response)
                print(f"📤 发送响应数据: {response.hex()}")
            
        except Exception as e:
            print(f"❌ 处理客户端请求失败: {str(e)}")
        finally:
            client_socket.close()
    
    def _process_melsec_request(self, request_data):
        """处理 Melsec 请求并生成响应"""
        try:
            # 简化的 MC 协议解析
            if len(request_data) < 11:
                return None
            
            # MC协议格式 (Binary模式)
            # 子头部: 2字节 (50 00)
            # 网络号: 1字节 (00)
            # PLC号: 1字节 (FF)
            # IO号: 2字节 (FF 03)
            # 站号: 1字节 (00)
            # 请求数据长度: 2字节
            # 请求数据: N字节
            
            # 跳过头部，获取命令码
            cmd_code = struct.unpack('<H', request_data[9:11])[0]
            
            print(f"🔍 解析命令: CMD=0x{cmd_code:04X}")
            
            # 根据命令码处理
            if cmd_code == 0x0401:  # 位单位批量读取
                return self._handle_bit_read(request_data)
            elif cmd_code == 0x1401:  # 字单位批量读取
                return self._handle_word_read(request_data)
            elif cmd_code == 0x1402:  # 字单位批量写入
                return self._handle_word_write(request_data)
            elif cmd_code == 0x0402:  # 位单位批量写入
                return self._handle_bit_write(request_data)
            else:
                print(f"❓ 未知命令码: 0x{cmd_code:04X}")
                return self._create_error_response()
            
        except Exception as e:
            print(f"❌ 处理 Melsec 请求失败: {str(e)}")
            return self._create_error_response()
    
    def _handle_bit_read(self, request_data):
        """处理位读取"""
        try:
            # 解析地址和点数
            device_code = request_data[11]  # 设备代码
            address = struct.unpack('<I', request_data[12:15] + b'\x00')[0]  # 地址 (3字节)
            points = struct.unpack('<H', request_data[15:17])[0]  # 点数
            
            print(f"📖 位读取: 设备=0x{device_code:02X}, 地址={address}, 点数={points}")
            
            # M设备 (0x90)
            if device_code == 0x90:
                result_data = b''
                for i in range(points):
                    bit_addr = address + i
                    bit_value = self.memory_areas['M'].get(bit_addr, False)
                    result_data += struct.pack('B', 1 if bit_value else 0)
                
                return self._create_success_response(result_data)
            
            return self._create_error_response()
            
        except Exception as e:
            print(f"❌ 位读取失败: {str(e)}")
            return self._create_error_response()
    
    def _handle_word_read(self, request_data):
        """处理字读取"""
        try:
            # 解析地址和点数
            device_code = request_data[11]  # 设备代码
            address = struct.unpack('<I', request_data[12:15] + b'\x00')[0]  # 地址 (3字节)
            points = struct.unpack('<H', request_data[15:17])[0]  # 点数
            
            print(f"📖 字读取: 设备=0x{device_code:02X}, 地址={address}, 点数={points}")
            
            # D设备 (0xA8)
            if device_code == 0xA8:
                result_data = b''
                for i in range(points):
                    word_addr = address + i
                    word_value = self.memory_areas['D'].get(word_addr, 0)
                    result_data += struct.pack('<H', word_value)
                
                return self._create_success_response(result_data)
            
            return self._create_error_response()
            
        except Exception as e:
            print(f"❌ 字读取失败: {str(e)}")
            return self._create_error_response()
    
    def _handle_bit_write(self, request_data):
        """处理位写入"""
        try:
            # 解析地址和点数
            device_code = request_data[11]  # 设备代码
            address = struct.unpack('<I', request_data[12:15] + b'\x00')[0]  # 地址 (3字节)
            points = struct.unpack('<H', request_data[15:17])[0]  # 点数
            
            print(f"✏️ 位写入: 设备=0x{device_code:02X}, 地址={address}, 点数={points}")
            
            # M设备 (0x90)
            if device_code == 0x90:
                data_start = 17
                for i in range(points):
                    bit_addr = address + i
                    bit_value = request_data[data_start + i] != 0
                    self.memory_areas['M'][bit_addr] = bit_value
                    print(f"  M{bit_addr} = {bit_value}")
                
                return self._create_success_response(b'')
            
            return self._create_error_response()
            
        except Exception as e:
            print(f"❌ 位写入失败: {str(e)}")
            return self._create_error_response()
    
    def _handle_word_write(self, request_data):
        """处理字写入"""
        try:
            # 解析地址和点数
            device_code = request_data[11]  # 设备代码
            address = struct.unpack('<I', request_data[12:15] + b'\x00')[0]  # 地址 (3字节)
            points = struct.unpack('<H', request_data[15:17])[0]  # 点数
            
            print(f"✏️ 字写入: 设备=0x{device_code:02X}, 地址={address}, 点数={points}")
            
            # D设备 (0xA8)
            if device_code == 0xA8:
                data_start = 17
                for i in range(points):
                    word_addr = address + i
                    word_value = struct.unpack('<H', request_data[data_start + i*2:data_start + i*2 + 2])[0]
                    self.memory_areas['D'][word_addr] = word_value
                    print(f"  D{word_addr} = {word_value}")
                
                return self._create_success_response(b'')
            
            return self._create_error_response()
            
        except Exception as e:
            print(f"❌ 字写入失败: {str(e)}")
            return self._create_error_response()
    
    def _create_success_response(self, data=b''):
        """创建成功响应"""
        # MC协议响应格式
        header = b'\xD0\x00'  # 子头部
        header += b'\x00'      # 网络号
        header += b'\xFF'      # PLC号  
        header += b'\xFF\x03'  # IO号
        header += b'\x00'      # 站号
        
        # 响应数据长度
        response_length = 2 + len(data)  # 完成码2字节 + 数据
        header += struct.pack('<H', response_length)
        
        # 完成码 (成功)
        response = header + b'\x00\x00' + data
        
        return response
    
    def _create_error_response(self):
        """创建错误响应"""
        # MC协议错误响应
        header = b'\xD0\x00'  # 子头部
        header += b'\x00'      # 网络号
        header += b'\xFF'      # PLC号  
        header += b'\xFF\x03'  # IO号
        header += b'\x00'      # 站号
        header += struct.pack('<H', 2)  # 响应长度
        
        # 错误码
        response = header + b'\x01\xC0'  # 通用错误
        
        return response


def start_mock_melsec_server():
    """启动模拟 Melsec 服务器"""
    server = MockMelsecServer('127.0.0.1', 5007)
    server.start()
    return server


if __name__ == "__main__":
    print("🚀 启动 Melsec 模拟设备服务器")
    print("=" * 50)
    
    try:
        # 启动模拟服务器
        server = start_mock_melsec_server()
        
        print("\n📋 测试说明:")
        print("  可以在在线脚本中使用以下代码测试:")
        print("")
        print("  # 测试读取 boolean")
        print("  result = VWED.melsec.read_boolean('127.0.0.1', 5007, 'M100')")
        print("  print(f'读取 M100 结果: {result}')  # 期望: True")
        print("")
        print("  # 测试读取 number")
        print("  result = VWED.melsec.read_number('127.0.0.1', 5007, 'D100')")
        print("  print(f'读取 D100 结果: {result}')  # 期望: 1234")
        print("")
        print("  # 测试写入 boolean")
        print("  success = VWED.melsec.write_boolean('127.0.0.1', 5007, 'M200', True)")
        print("  print(f'写入 M200 结果: {success}')  # 期望: True")
        print("")
        print("  # 测试写入 number")
        print("  success = VWED.melsec.write_number('127.0.0.1', 5007, 'D200', 8888)")
        print("  print(f'写入 D200 结果: {success}')  # 期望: True")
        print("")
        print("  # 测试读取 string")
        print("  result = VWED.melsec.read_string('127.0.0.1', 5007, 'D500', 10)")
        print("  print(f'读取 D500 字符串结果: {result}')  # 期望: 'HELLO'")
        print("")
        print("💡 按 Ctrl+C 停止服务器")
        
        # 保持服务器运行
        while True:
            time.sleep(1)
            
    except KeyboardInterrupt:
        print("\n⏹️ 收到停止信号")
    except Exception as e:
        print(f"\n❌ 服务器运行失败: {str(e)}")
    finally:
        if 'server' in locals():
            server.stop()
        print("👋 再见!")