package co.dc.aptiv.mina;

import java.net.InetSocketAddress;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.AbstractIoConnector;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFactory;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.serial.SerialAddress;
import org.apache.mina.transport.serial.SerialAddress.DataBits;
import org.apache.mina.transport.serial.SerialAddress.FlowControl;
import org.apache.mina.transport.serial.SerialAddress.Parity;
import org.apache.mina.transport.serial.SerialAddress.StopBits;
import org.apache.mina.transport.serial.SerialConnector;
import org.apache.mina.transport.socket.nio.NioSocketConnector;


public class MinaAbstract {

    private static final Log log = LogFactory.getLog(MinaAbstract.class);
    @Resource
    protected QueryRunner queryRunner;
    protected AbstractIoConnector connector = null;
    protected IoSession session = null;
    protected String ip;
    protected int port = 8500;
    protected ProtocolCodecFactory protocolCodecFactory = null;
    protected boolean isCom232;
    protected boolean isOn = false;


    ScheduledThreadPoolExecutor stpe = new ScheduledThreadPoolExecutor(2);

    public void init(boolean init) {
        if (isCom232) {
            // 创建连接客户端
            connector = new SerialConnector();
            connector.getFilterChain().addLast("log", new LoggingFilter());
            if (protocolCodecFactory != null) {
                connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(protocolCodecFactory));
            }
            // 读写都空闲时间:30秒
            connector.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 30);
            // 发送缓冲区1M
            connector.getSessionConfig().setReadBufferSize(1024 * 1024);
            // connector.getSessionConfig().setReceiveBufferSize(1024 * 1024);//
            // 接收缓冲区1M
            // 设置连接超时检查时间
            connector.setConnectTimeoutCheckInterval(30);
            // 添加处理器
            connector.setHandler(new MinaAbstractHandler(this, queryRunner));

            log.info("com232 main服务启动ip[" + getIp() + "] port[" + getPort() + "]");

            SerialAddress address = new SerialAddress(getIp(), getPort(), DataBits.DATABITS_8, StopBits.BITS_1, Parity.NONE, FlowControl.NONE);

            connector.setDefaultRemoteAddress(address);
            if (init == true) {
                createConn();
            }
        } else {
            // 创建连接客户端
            connector = new NioSocketConnector();
            connector.getFilterChain().addLast("log", new LoggingFilter());
            connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new MessageCodecFactory(true, true)));
            // 读写都空闲时间:30秒
            connector.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 30);
            // 发送缓冲区1M
            connector.getSessionConfig().setReadBufferSize(1024 * 1024);
            // connector.getSessionConfig().setReceiveBufferSize(1024 * 1024);//
            // 接收缓冲区1M
            // 设置连接超时检查时间
            connector.setConnectTimeoutCheckInterval(30);
            // 添加处理器
            connector.setHandler(new MinaAbstractHandler(this, queryRunner));
            // setIp(systemParamService.getVal("BoxIp"));
            // setPort(Integer.parseInt(systemParamService.getVal("BoxListen")));
            log.info("tcp main服务启动ip[" + getIp() + "] port[" + getPort() + "]");
            connector.setDefaultRemoteAddress(new InetSocketAddress(getIp(), getPort()));
            if (init == true) {
                createConn();
            }
        }

    }

    /**
     * 重新建立连接
     */
    public boolean createConn() {
        try {
            if (session != null) {
                log.info("session.isClosing()>>>" + session.isClosing() + "   session.isConnected()>>>" + session.isConnected());
            }
            if (session == null || session.isClosing() == true
                    || session.isConnected() == false) {
                if (session != null) {
                    try {
                        session.close(true);
                    } catch (Exception e) {
                        log.error("session关闭出现异常---->>" + e.getMessage(), e);
                    }
                }
                if (connector == null) {
                    init(false);
                }
                // 启动自检线程
                // 建立连接
                ConnectFuture cf = connector.connect();
                // 等待连接创建完成
                cf.awaitUninterruptibly();
                session = cf.getSession();
                if (session.isConnected()) {
                    return true;
                } else {
                    return false;
                }
            }

        } catch (Exception e) {
            log.error(connector.toString() + " 建立连接失败", e);

        }
        return false;
    }

    public void send(String message) {
        try {
            if (isConnect() == false) {
                // 重连
                createConn();
            }
            if (isConnect()) {
                session.write(message);
            } else {
                log.info("连接失败");
            }

        } catch (Exception e) {
            log.error("发送失败！！！！！！！！！！", e);
        }
    }

    public Object receivedShort(Object obj) {
        return obj;
    }


    /**
     * @param message
     * @return 1成功 2超时 -1异常
     */
    public int sendByte(byte[] message) {
        try {
            if (session == null || session.isClosing() == true || session.isConnected() == false) {
                // 重连
                createConn();
            }
            if (isConnect()) {
                session.write(IoBuffer.wrap(message));
                return 1;
            } else {
                log.info("连接失败");
            }

        } catch (Exception e) {
            log.error("发送失败！！！！！！！！！！", e);
        }
        return -1;
    }


    /**
     * 重连
     */
    public synchronized void reset() {
        if (isConnect()) {
            return;
        }
        for (; ; ) {
            log.info("网络断开，开始重连...");
            if (isOn() == false) {
                break;
            }
            boolean isok = createConn();
            if (isok) {
                log.info("重连成功");
                break;
            }
            try {
                Thread.sleep(1000 * 15);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 关闭
     */
    public void closeConnection() {
        setOn(false);
        if (session != null) {
            session.close(true);
        }
        session = null;
        connector = null;
        if (stpe != null) {
            stpe.shutdownNow();
        }

    }


    public void startConnection() {
        setOn(true);
        //先开始创建连接
        createConn();

        stpe.scheduleWithFixedDelay(new Runnable() {
            public void run() {
                try {
                    log.info(getClass().getName() + " 开始自检连接状态 task start");
                    if (isOn()) {

                        reset();
                    }
                } catch (Exception e) {
                    log.error("开始自检连接状态 task error", e);
                }
            }
        }, 30, 30, TimeUnit.SECONDS);
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public ProtocolCodecFactory getProtocolCodecFactory() {
        return protocolCodecFactory;
    }

    public void setProtocolCodecFactory(ProtocolCodecFactory protocolCodecFactory) {
        this.protocolCodecFactory = protocolCodecFactory;
    }

    public IoSession getSession() {
        return session;
    }

    public void setSession(IoSession session) {
        this.session = session;
    }

    public boolean isConnect() {
        if (session != null && session.isConnected()) {
            return true;
        } else {
            return false;
        }
    }

    public boolean isOn() {
        return isOn;
    }

    public void setOn(boolean isOn) {
        this.isOn = isOn;
    }

}
