/*
 * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * WSO2 Inc. licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.wso2.carbon.device.mgt.mobile.impl.ios.dao.impl;

import org.wso2.carbon.device.mgt.ios.core.bean.ChallengeTokenBean;
import org.wso2.carbon.device.mgt.mobile.impl.ios.dao.IOSDAOFactory;
import org.wso2.carbon.device.mgt.mobile.impl.ios.dao.MobileDeviceManagementDAOException;
import org.wso2.carbon.device.mgt.mobile.impl.ios.dao.util.MobileDeviceManagementDAOUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * This is a data access object which is used to persist and retrieve challenge token information which is used in the
 * IOS device enrollment process.
 */
public class IOSEnrollmentTokenDAO {
    /**
     * Persists the challenge token bean
     *
     * @param challengeTokenBean {@link ChallengeTokenBean}
     * @return Boolean whether the operation is successful or not.
     * @throws MobileDeviceManagementDAOException
     */
    public boolean add(ChallengeTokenBean challengeTokenBean) throws MobileDeviceManagementDAOException {
        PreparedStatement stmt = null;
        try {
            Connection conn = IOSDAOFactory.getConnection();
            String sql = "INSERT INTO IOS_ENROLLMENT_TOKEN(TENANT_DOMAIN, CHALLENGE_TOKEN, DEVICE_ID, "
                    + "ACCESS_TOKEN, REFRESH_TOKEN, USERNAME, CLIENT_CREDENTIALS) VALUES (?, ?, ?, ?, ?, ?, ?)";
            stmt = conn.prepareStatement(sql);
            stmt.setString(1, challengeTokenBean.getDomain());
            stmt.setString(2, challengeTokenBean.getChallengeToken());
            stmt.setString(3, challengeTokenBean.getDeviceID());
            stmt.setString(4, challengeTokenBean.getAccessToken());
            stmt.setString(5, challengeTokenBean.getRefreshToken());
            stmt.setString(6, challengeTokenBean.getUsername());
            stmt.setString(7, challengeTokenBean.getClient());
            stmt.executeUpdate();
        } catch (SQLException e) {
            throw new MobileDeviceManagementDAOException("Error occurred while persisting the challenge token.", e);
        } finally {
            MobileDeviceManagementDAOUtil.cleanupResources(stmt, null);
        }
        return true;
    }

    /**
     * Updates the challenge token bean with device identifier.
     *
     * @param challengeTokenBean {@link ChallengeTokenBean}
     * @return Boolean whether the operation succeeded.
     * @throws MobileDeviceManagementDAOException
     */
    public boolean update(ChallengeTokenBean challengeTokenBean) throws MobileDeviceManagementDAOException {
        PreparedStatement stmt = null;
        try {
            Connection conn = IOSDAOFactory.getConnection();
            String sql = "UPDATE IOS_ENROLLMENT_TOKEN SET TENANT_DOMAIN = ?, DEVICE_ID = ?, ACCESS_TOKEN = ?,"
                    + " REFRESH_TOKEN = ?, USERNAME = ?, CLIENT_CREDENTIALS = ? WHERE CHALLENGE_TOKEN = ?";
            stmt = conn.prepareStatement(sql);
            stmt.setString(1, challengeTokenBean.getDomain());
            stmt.setString(2, challengeTokenBean.getDeviceID());
            stmt.setString(3, challengeTokenBean.getAccessToken());
            stmt.setString(4, challengeTokenBean.getRefreshToken());
            stmt.setString(5, challengeTokenBean.getUsername());
            stmt.setString(6, challengeTokenBean.getClient());
            stmt.setString(7, challengeTokenBean.getChallengeToken());
            stmt.executeUpdate();
        } catch (SQLException e) {
            throw new MobileDeviceManagementDAOException("Error occurred while updating the challenge token.", e);
        } finally {
            MobileDeviceManagementDAOUtil.cleanupResources(stmt, null);
        }
        return true;
    }

    /**
     * Retrieve challenge token information.
     *
     * @param challengeToken challengeToken
     * @return {@link ChallengeTokenBean}
     * @throws MobileDeviceManagementDAOException
     */
    public ChallengeTokenBean get(String challengeToken) throws MobileDeviceManagementDAOException {
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try {
            Connection conn = IOSDAOFactory.getConnection();
            String sql = "SELECT TENANT_DOMAIN, CHALLENGE_TOKEN, DEVICE_ID, ACCESS_TOKEN," +
                    " REFRESH_TOKEN, USERNAME, CLIENT_CREDENTIALS FROM IOS_ENROLLMENT_TOKEN WHERE " +
                    "CHALLENGE_TOKEN = ?";
            stmt = conn.prepareStatement(sql);
            stmt.setString(1, challengeToken);
            rs = stmt.executeQuery();
            return generateTokenBean(rs);
        } catch (SQLException e) {
            throw new MobileDeviceManagementDAOException("Error occurred while fetching the challenge token.", e);
        } finally {
            MobileDeviceManagementDAOUtil.cleanupResources(stmt, rs);
        }
    }

    /**
     * Retrieve challenge token information.
     *
     * @param deviceId device identifier
     * @return {@link ChallengeTokenBean}
     * @throws MobileDeviceManagementDAOException
     */
    public ChallengeTokenBean getByDeviceId(String deviceId) throws MobileDeviceManagementDAOException {
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try {
            Connection conn = IOSDAOFactory.getConnection();
            String sql = "SELECT TENANT_DOMAIN, CHALLENGE_TOKEN, DEVICE_ID, ACCESS_TOKEN," +
                    " REFRESH_TOKEN, USERNAME, CLIENT_CREDENTIALS FROM IOS_ENROLLMENT_TOKEN WHERE " +
                    "DEVICE_ID = ?";
            stmt = conn.prepareStatement(sql);
            stmt.setString(1, deviceId);
            rs = stmt.executeQuery();
            return generateTokenBean(rs);
        } catch (SQLException e) {
            throw new MobileDeviceManagementDAOException("Error occurred while fetching the challenge token.", e);
        } finally {
            MobileDeviceManagementDAOUtil.cleanupResources(stmt, rs);
        }
    }

    /**
     * Deletes challenge token entry.
     *
     * @param deviceId     deviceId
     * @return Boolean if the operation succeeded.
     * @throws MobileDeviceManagementDAOException
     */
    public boolean delete(String deviceId) throws MobileDeviceManagementDAOException {
        PreparedStatement stmt = null;
        try {
            Connection conn = IOSDAOFactory.getConnection();
            String sql = "DELETE FROM IOS_ENROLLMENT_TOKEN WHERE DEVICE_ID = ?";
            stmt = conn.prepareStatement(sql);
            stmt.setString(1, deviceId);
            stmt.executeUpdate();
        } catch (SQLException e) {
            throw new MobileDeviceManagementDAOException("Error occurred while deleting the challenge token.", e);
        } finally {
            MobileDeviceManagementDAOUtil.cleanupResources(stmt, null);
        }
        return true;
    }

    /**
     * Generates {@link ChallengeTokenBean} from the result set.
     *
     * @param rs {@link ResultSet}
     * @return {@link ChallengeTokenBean}
     * @throws SQLException
     */
    private ChallengeTokenBean generateTokenBean(ResultSet rs) throws SQLException {
        ChallengeTokenBean challengeTokenBean = new ChallengeTokenBean();
        while (rs.next()) {
            challengeTokenBean.setChallengeToken(rs.getString("CHALLENGE_TOKEN"));
            challengeTokenBean.setDomain(rs.getString("TENANT_DOMAIN"));
            challengeTokenBean.setDeviceID(rs.getString("DEVICE_ID"));
            challengeTokenBean.setAccessToken(rs.getString("ACCESS_TOKEN"));
            challengeTokenBean.setRefreshToken(rs.getString("REFRESH_TOKEN"));
            challengeTokenBean.setUsername(rs.getString("USERNAME"));
            challengeTokenBean.setClient(rs.getString("CLIENT_CREDENTIALS"));
        }
        if (challengeTokenBean.getChallengeToken() == null) {
            return null;
        }
        return challengeTokenBean;
    }
}