# -*- coding:utf-8 -*-
import os, sys, time
import abc
import socket
import json
import numpy as np
import struct
import binascii

#创建ProHeader数据类型
# 定义:
DataHeader = np.dtype({'names': ['protocol', 'len', 'cmd'], 'formats': ['u1', 'u4', 'u1']}, align=False)
UserInfo = np.dtype({'names': ['userName', 'password', 'actuator'], 'formats': ['|S260', '|S260', '|S260']}, align=False)
LoginResp = np.dtype({'names': ['bStatus', 'szMessage'], 'formats': ['?', '|S260']}, align=False)
# 通知SATService正常关机、重启;
NoticeResp = np.dtype({'names': ['TimeStamp', 'NoticeType'], 'formats': ['u8', 'u4']}, align=False)

class BaseClient(object):
    __metaclass__ = abc.ABCMeta

    def __init__(self):
        """设备id"""
        self.device_id = 1
        '''设备名称'''
        self.device_name = "name"
        '''设备命令'''
        self.device_cmd = "rtn 11;"
        '''设备通讯超时值:毫秒'''
        self.device_timeout = 300

        '''通信sock'''
        self.sock = None
        '''通信端口号'''
        self.port = 5588
        '''通信状态'''
        self.constate = False

    def __def__(self):
        self.disconnect()

    '''连接服务器'''
    def connect(self):
        try:
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.sock.connect(('127.0.0.1', self.port))  # 没有返回值;
            self.sock.sendall("2222")
            self.constate = True
        except Exception, e:
            print "BaseClient=> socket connect error:", e, self.port
            self.constate = False

        return self.constate

    # 发送消息;
    def sendmsg(self):
        '''是否连接'''
        if self.constate is False:
            if self.connect() is False:
                return None

        '''拼装要发送的数据包'''
        userinfo = np.array([("superAdmin", "123456")], dtype=UserInfo)

        '''发送请求数据'''
        try:
            self.sock.settimeout(5)
            phead = np.array([(0xAA, userinfo.itemsize + np.array([(0xAA, 0, 0x01)], dtype=DataHeader).itemsize, 0x00)], dtype=DataHeader)
            '''一次性发送完整包'''
            # self.sock.sendall(bytearray(phead.tobytes() + bytes(msg_json)))
            '''分包发送:头、体'''
            self.sock.sendall(phead.tobytes())
            self.sock.sendall(userinfo.tobytes())
            self.sock.settimeout(None)
        except Exception, e:
            print "BaseClient=> send Error:", e
            self.disconnect()
            self.connect()
            return None
        
        '''接收返回数据'''
        try:
            # 等待数据返回;(串口若请求失败,超时值应该设置在3秒以上)
            self.sock.settimeout(10)
            data = bytes(self.sock.recv(1024 * 8))
            print "recv:" + binascii.hexlify(data)
            self.sock.settimeout(None)

            phead = data[0: np.array([(0xAA, 0, 0x01)], dtype=DataHeader).itemsize]
            respone = data[np.array([(0xAA, 0, 0x01)], dtype=DataHeader).itemsize:]
            print "respone:" + binascii.hexlify(respone)
            '''小端<I, 大端>I, 网络端 !'''
            protocol, len, cmd = struct.unpack('<BIB', phead)
            status, message = int(struct.unpack('<c', respone))
            '''返回头是否有效'''
            if protocol != 0xAA and len != data.__len__():
                return None
            
            return status
        except Exception, e:
            print "BaseClient=> recv Error:", e
            return None

    '''断开连接'''
    def disconnect(self):
        try:
            self.sock.shutdown(2)
            self.sock.close()
        except Exception, e:
            print "BaseClient=> socket disconnect error:", e


class SATClient(object):

    __metaclass__ = abc.ABCMeta

    def __init__(self):
        '''通信sock'''
        self.sock = None
        '''通信端口号'''
        self.port = 5599
        '''通信状态'''
        self.constate = False

    def __def__(self):
        self.disconnect()

    '''连接服务器'''

    def connect(self):
        try:
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.sock.connect(('127.0.0.1', self.port))  # 没有返回值;
            self.sock.sendall("2222")
            self.constate = True
        except Exception, e:
            print "BaseClient=> socket connect error:", e, self.port
            self.constate = False

        return self.constate

    # 发送消息;
    def sendmsg(self):
        '''是否连接'''
        if self.constate is False:
            if self.connect() is False:
                return None

        '''拼装要发送的数据包'''
        userinfo = np.array([("superAdmin", "123456", "SAT-Admin")], dtype=UserInfo)

        '''发送请求数据'''
        try:
            self.sock.settimeout(5)
            phead = np.array([(0xAA, userinfo.itemsize + np.array([(0xAA, 0, 0x01)], dtype=DataHeader).itemsize, 0x00)],
                             dtype=DataHeader)
            '''一次性发送完整包'''
            # self.sock.sendall(bytearray(phead.tobytes() + bytes(msg_json)))
            '''分包发送:头、体'''
            self.sock.sendall(phead.tobytes())
            self.sock.sendall(userinfo.tobytes())
            self.sock.settimeout(None)
        except Exception, e:
            print "BaseClient=> send Error:", e
            self.disconnect()
            self.connect()
            return False

        # time.sleep(0.1)
        # return False
        '''接收返回数据'''
        try:
            # 等待数据返回;(串口若请求失败,超时值应该设置在3秒以上)
            self.sock.settimeout(10)
            data = bytes(self.sock.recv(1024 * 8))
            # print "recv:" + binascii.hexlify(data)
            self.sock.settimeout(None)

            phead = data[0: np.array([(0xAA, 0, 0x01)], dtype=DataHeader).itemsize]
            respone = data[np.array([(0xAA, 0, 0x01)], dtype=DataHeader).itemsize:]

            '''
            注意:坑!
                如果respone此时只返回16进制字符 '\x01',Python的字符与C++的不一样,字符就是字符;
                要将16进制字符转成整型,使用ord函数
            '''
            # print "respone:" + binascii.hexlify(respone)
            '''小端<I, 大端>I, 网络端 !'''
            protocol, len, cmd = struct.unpack('<BIB', phead)
            # loginresult = ord(struct.unpack('<c', respone)[0])
            status, message = struct.unpack('<?260s', respone)
            '''返回头是否有效'''
            if protocol != 0xAA and len != data.__len__():
                return False

            return status
        except Exception, e:
            print "BaseClient=> recv Error:", e
            return False
            
            
    # 发送通知,不接收返回;
    def sendnotice(self, type):
        '''是否连接'''
        if self.constate is False:
            if self.connect() is False:
                return None

        '''拼装要发送的数据包'''
        notice = np.array([(time.time(), type)], dtype=NoticeResp)

        '''发送请求数据'''
        try:
            self.sock.settimeout(5)
            phead = np.array([(0xAA, notice.itemsize + np.array([(0xAA, 0, 0x01)], dtype=DataHeader).itemsize, 0x06)], dtype=DataHeader)
            '''一次性发送完整包'''
            self.sock.sendall(bytearray(phead.tobytes() + notice.tobytes()))
            self.sock.settimeout(None)
        except Exception, e:
            print "BaseClient=> send Error:", e
            self.disconnect()
            self.connect()
            return False
       

    '''断开连接'''

    def disconnect(self):
        try:
            self.sock.shutdown(2)
            self.sock.close()
        except Exception, e:
            print "BaseClient=> socket disconnect error:", e


if __name__ == "__main__":
    bc = SATClient()
    while 1:
        print bc.sendmsg()

    print "ok!"