package id.iptek.utms.agent.dao;

import id.iptek.utms.agent.db.DBConn;
import id.iptek.utms.agent.db.DBUtil;
import id.iptek.utms.agent.db.DatabaseException;
import id.iptek.utms.agent.model.CellInfo;
import id.iptek.utms.agent.model.HeartBeat;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author Jaka
 */
public class HeartbeatDao {

    private Logger logger = LoggerFactory.getLogger(HeartbeatDao.class);
    
    public HeartbeatDao() {
    }

    public boolean save(HeartBeat hearbeat) throws DatabaseException {
        boolean saved = false;
        Connection conn = null;
        try {
            conn = DBConn.getInstance().getConnection();
            conn.setAutoCommit(false);

            // save heartbeat first
            saved |= saveHeartBeat(conn, hearbeat);
            if (saved) {
                saved |= updateTerminalLastHearbeat(conn, hearbeat);
            }

            conn.commit();
            conn.setAutoCommit(true);
        } catch (SQLException ex) {
            DBUtil.rollback(conn);
            throw new DatabaseException(ex);
        } finally {
            DBUtil.close(conn);
        }
        return saved;
    }

    public Connection getDBConnection() throws SQLException {
        Connection conn = DBConn.getInstance().getConnection();
        return conn;
    }
    
    public boolean saveHeartBeat(Connection conn, HeartBeat heartbeat) throws SQLException {
        boolean saved = false;
        PreparedStatement pstmt = null;
        try {
            pstmt = conn.prepareStatement(""
                    + "insert into tms_heart_beat (id,sn,battery_temp,battery_percentage,latitude,longitude,cell_name,cell_type,cell_strength,create_ts,created_by,version)  "
                    + "values (?::uuid,?,?,?,?,?,?,?,?,?,?,1) ");
            int idx = 1;
            pstmt.setString(idx++, heartbeat.getId());
            pstmt.setString(idx++, heartbeat.getDeviceSn());
            pstmt.setDouble(idx++, heartbeat.getDiagnosticInfo().getBatteryTemp());
            pstmt.setDouble(idx++, heartbeat.getDiagnosticInfo().getBatteryPercentage());
            pstmt.setDouble(idx++, heartbeat.getLocationInfo().getLat());
            pstmt.setDouble(idx++, heartbeat.getLocationInfo().getLng());
            if(heartbeat.getCellInfo() != null && !heartbeat.getCellInfo().isEmpty()) {
                CellInfo cellInfo = heartbeat.getCellInfo().get(0);
                pstmt.setString(idx++, cellInfo.getName());
                pstmt.setString(idx++, cellInfo.getType());
                pstmt.setInt(idx++, cellInfo.getStrength());
            } else {
                pstmt.setNull(idx++, java.sql.Types.VARCHAR);
                pstmt.setNull(idx++, java.sql.Types.VARCHAR);
                pstmt.setNull(idx++, java.sql.Types.INTEGER);
            }
            pstmt.setTimestamp(idx++, new java.sql.Timestamp(heartbeat.getCreateTime().getTime()));
            pstmt.setString(idx++, "system");
            //saved = pstmt.executeUpdate() == 1;
            saved = pstmt.executeUpdate() >= 0;
        } finally {
            DBUtil.close(pstmt);
        }
        return saved;
    }

    public boolean saveAll(List<HeartBeat> hearbeats) throws DatabaseException {
        boolean saved = false;
        Connection conn = null;
        try {
            conn = DBConn.getInstance().getConnection();
            conn.setAutoCommit(false);

            // save heartbeat first
            saved |= saveHeartBeats(conn, hearbeats);
            if (saved) {
                saved |= updateTerminalLastHearbeats(conn, hearbeats);
            }

            conn.commit();
            conn.setAutoCommit(true);
        } catch (SQLException ex) {
            DBUtil.rollback(conn);
            throw new DatabaseException(ex);
        } finally {
            DBUtil.close(conn);
        }
        return saved;
    }

    private boolean saveHeartBeats(Connection conn, List<HeartBeat> heartbeats) throws SQLException {
        boolean saved = false;
        PreparedStatement pstmt = null;
        try {
            pstmt = conn.prepareStatement(""
                    + "insert into tms_heart_beat (id,sn,battery_temp,battery_percentage,latitude,longitude,cell_name,cell_type,cell_strength,create_ts,created_by,version)  "
                    + "values (?::uuid,?,?,?,?,?,?,?,?,?,?,1) ");
            for(HeartBeat heartbeat : heartbeats) {
                int idx = 1;
                pstmt.setString(idx++, heartbeat.getId());
                pstmt.setString(idx++, heartbeat.getDeviceSn());
                pstmt.setDouble(idx++, heartbeat.getDiagnosticInfo().getBatteryTemp());
                pstmt.setDouble(idx++, heartbeat.getDiagnosticInfo().getBatteryPercentage());
                pstmt.setDouble(idx++, heartbeat.getLocationInfo().getLat());
                pstmt.setDouble(idx++, heartbeat.getLocationInfo().getLng());
                if(heartbeat.getCellInfo() != null && !heartbeat.getCellInfo().isEmpty()) {
                    CellInfo cellInfo = heartbeat.getCellInfo().get(0);
                    pstmt.setString(idx++, cellInfo.getName());
                    pstmt.setString(idx++, cellInfo.getType());
                    pstmt.setInt(idx++, cellInfo.getStrength());
                } else {
                    pstmt.setNull(idx++, java.sql.Types.VARCHAR);
                    pstmt.setNull(idx++, java.sql.Types.VARCHAR);
                    pstmt.setNull(idx++, java.sql.Types.INTEGER);
                }
                pstmt.setTimestamp(idx++, new java.sql.Timestamp(heartbeat.getCreateTime().getTime()));
                pstmt.setString(idx++, "system");
                pstmt.addBatch();
                pstmt.clearParameters();
            }
            int[] xs = pstmt.executeBatch();
            int affectedRows = 0;
            for(int x : xs) {
                affectedRows += x;
            }
            //saved = affectedRows > 0;
            saved = affectedRows >= 0;
        } finally {
            DBUtil.close(pstmt);
        }
        return saved;
    }
    
    private boolean updateTerminalLastHearbeat(Connection conn, HeartBeat heartbeat) throws SQLException {
        boolean saved = false;
        PreparedStatement pstmt = null;
        try {
            pstmt = conn.prepareStatement(""
                    + "update tms_last_heartbeat set heart_beat_id=?::uuid,update_ts=now() where terminal_sn=?");
            pstmt.setString(1, heartbeat.getId());
            pstmt.setString(2, heartbeat.getDeviceSn());
            saved = pstmt.executeUpdate() == 1;
        } finally {
            DBUtil.close(pstmt);
        }
        return saved;
    }
    
    private boolean updateTerminalLastHearbeats(Connection conn, List<HeartBeat> heartbeats) throws SQLException {
        boolean saved = false;
        PreparedStatement pstmt = null;
        try {
            pstmt = conn.prepareStatement(""
                    + "update tms_last_heartbeat set heart_beat_id=?::uuid,update_ts=now() where terminal_sn=?");
            for(HeartBeat heartbeat : heartbeats) {
                pstmt.setString(1, heartbeat.getId());
                pstmt.setString(2, heartbeat.getDeviceSn());
                pstmt.addBatch();
                pstmt.clearParameters();
            }
            int[] xs = pstmt.executeBatch();
            int affectedRows = 0;
            for(int x : xs) {
                affectedRows += x;
            }
            saved = affectedRows > 0;
        } finally {
            DBUtil.close(pstmt);
        }
        return saved;
    }

}
