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

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.PaginationResult;
import org.wso2.carbon.device.mgt.ios.payload.beans.DeviceProfile;
import org.wso2.carbon.device.mgt.ios.payload.exception.PListException;
import org.wso2.carbon.device.mgt.ios.payload.exception.ProfileConfigurationException;
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.ProfileDAO;
import org.wso2.carbon.device.mgt.mobile.impl.ios.dto.DEPDevice;
import org.wso2.carbon.device.mgt.mobile.impl.ios.dto.DEPProfile;

import java.util.List;

public class IOSProfileServiceImpl implements IOSProfileService {

    private static final Log log = LogFactory.getLog(IOSProfileServiceImpl.class);
    private static ProfileDAO profileDAO;

    public IOSProfileServiceImpl() {
        this.profileDAO = new IOSDAOFactory().getProfileDAO();
    }

    @Override
    public void saveProfile(DeviceProfile deviceProfile) throws PListException {
        try {
            IOSDAOFactory.beginTransaction();
            this.profileDAO.addProfile(deviceProfile);
            IOSDAOFactory.commitTransaction();
        } catch (MobileDeviceManagementDAOException e) {
            try {
                IOSDAOFactory.rollbackTransaction();
            } catch (MobileDeviceManagementDAOException e1) {
                log.warn("Error occurred while roll-backing the transaction", e);
            }
            throw new PListException("Error occurred while adding the profile", e);
        } finally {
            IOSDAOFactory.closeConnection();
        }
    }

    @Override
    public DeviceProfile getProfile(String deviceId, String url) throws PListException{
        DeviceProfile deviceProfile;
        try {
            IOSDAOFactory.beginTransaction();
            deviceProfile = this.profileDAO.getProfile(deviceId, url);
            IOSDAOFactory.commitTransaction();
        } catch (MobileDeviceManagementDAOException e) {
            try {
                IOSDAOFactory.rollbackTransaction();
            } catch (MobileDeviceManagementDAOException e1) {
                log.warn("Error occurred while roll-backing the transaction", e);
            }
            throw new PListException("Error occurred while adding the profile", e);
        } finally {
            IOSDAOFactory.closeConnection();
        }
        return deviceProfile;
    }

    @Override
    public PaginationResult getDEPProfiles(PaginationRequest request) throws ProfileConfigurationException {
        List<DEPProfile> depProfiles;
        PaginationResult paginationResult = new PaginationResult();
        int count;
        try {
            IOSDAOFactory.getConnection();
            depProfiles = this.profileDAO.getDEPProfiles(request);
            count = this.profileDAO.getDEPProfilesCount();
            paginationResult.setData(depProfiles);
        } catch (MobileDeviceManagementDAOException e) {
            String msg = "Could not fetch the DEP profiles.";
            log.error(msg, e);
            throw new ProfileConfigurationException(msg, e);
        } finally {
            IOSDAOFactory.closeConnection();
        }
        paginationResult.setRecordsFiltered(count);
        paginationResult.setRecordsTotal(count);
        return paginationResult;
    }

    @Override
    public DEPProfile getDEPProfile(String uuid) throws ProfileConfigurationException {
        DEPProfile depProfiles;
        try {
            IOSDAOFactory.getConnection();
            depProfiles = this.profileDAO.getDEPProfile(uuid);
        } catch (MobileDeviceManagementDAOException e) {
            String msg = "Could not fetch the DEP profile with id:" + uuid;
            log.error(msg, e);
            throw new ProfileConfigurationException(msg, e);
        } finally {
            IOSDAOFactory.closeConnection();
        }
        return depProfiles;
    }

    @Override
    public int addDEPProfile(DEPProfile depProfile) throws ProfileConfigurationException {
        int id;
        try {
            IOSDAOFactory.beginTransaction();
            id = this.profileDAO.addDEPProfile(depProfile);
            IOSDAOFactory.commitTransaction();
        } catch (MobileDeviceManagementDAOException e) {
            try {
                IOSDAOFactory.rollbackTransaction();
            } catch (MobileDeviceManagementDAOException e1) {
                log.warn("Error occurred while roll-backing the transaction", e);
            }
            throw new ProfileConfigurationException("Error occurred while adding the profile", e);
        } finally {
            IOSDAOFactory.closeConnection();
        }
        return id;
    }

    @Override
    public boolean updateDEPProfile(DEPProfile depProfile) throws ProfileConfigurationException {
        boolean result;
        try {
            IOSDAOFactory.beginTransaction();
            result = this.profileDAO.updateDEPProfile(depProfile);
            IOSDAOFactory.commitTransaction();
        } catch (MobileDeviceManagementDAOException e) {
            try {
                IOSDAOFactory.rollbackTransaction();
            } catch (MobileDeviceManagementDAOException e1) {
                log.warn("Error occurred while roll-backing the transaction", e);
            }
            throw new ProfileConfigurationException("Error occurred while updating the profile", e);
        } finally {
            IOSDAOFactory.closeConnection();
        }
        return result;
    }

    @Override
    public boolean addDEPDevice(DEPDevice depDevice) throws ProfileConfigurationException {
        boolean status = false;
        try {
            IOSDAOFactory.beginTransaction();
            status = this.profileDAO.addDEPDevice(depDevice);
            IOSDAOFactory.commitTransaction();
        } catch (MobileDeviceManagementDAOException e) {
            try {
                IOSDAOFactory.rollbackTransaction();
            } catch (MobileDeviceManagementDAOException e1) {
                log.warn("Error occurred while roll-backing the transaction", e);
            }
            throw new ProfileConfigurationException("Error occurred while adding the profile", e);
        } finally {
            IOSDAOFactory.closeConnection();
        }
        return status;
    }

    @Override
    public boolean updateDEPDevice(DEPDevice depDevice) throws ProfileConfigurationException {
        boolean status = false;
        try {
            IOSDAOFactory.beginTransaction();
            status = this.profileDAO.updateDEPDevice(depDevice);
            IOSDAOFactory.commitTransaction();
        } catch (MobileDeviceManagementDAOException e) {
            try {
                IOSDAOFactory.rollbackTransaction();
            } catch (MobileDeviceManagementDAOException e1) {
                log.warn("Error occurred while roll-backing the transaction", e);
            }
            throw new ProfileConfigurationException("Error occurred while adding the profile", e);
        } finally {
            IOSDAOFactory.closeConnection();
        }
        return status;
    }

    @Override
    public void removeDEPDevices(List<String> serialNumbers) throws ProfileConfigurationException {
        try {
            IOSDAOFactory.beginTransaction();
            if (serialNumbers != null && !serialNumbers.isEmpty()) {
                for (String serial : serialNumbers) {
                    this.profileDAO.removeDEPDevice(serial);
                }
            }
            IOSDAOFactory.commitTransaction();
        } catch (MobileDeviceManagementDAOException e) {
            try {
                IOSDAOFactory.rollbackTransaction();
            } catch (MobileDeviceManagementDAOException e1) {
                log.warn("Error occurred while roll-backing the transaction", e);
            }
            throw new ProfileConfigurationException("Error occurred while deleting the device.", e);
        } finally {
            IOSDAOFactory.closeConnection();
        }
    }

    @Override
    public DEPDevice getDEPDevice(String serial) throws ProfileConfigurationException {
        DEPDevice depDevice;
        try {
            IOSDAOFactory.getConnection();
            depDevice = this.profileDAO.getDEPDevice(serial);
        } catch (MobileDeviceManagementDAOException e) {
            String msg = "Could not fetch the DEP device with serial:" + serial;
            log.error(msg, e);
            throw new ProfileConfigurationException(msg, e);
        } finally {
            IOSDAOFactory.closeConnection();
        }
        return depDevice;
    }

    @Override
    public PaginationResult getDEPDevices(PaginationRequest request) throws ProfileConfigurationException {
        List<DEPDevice> depDevices;
        PaginationResult paginationResult = new PaginationResult();
        int count = 0;
        try {
            IOSDAOFactory.getConnection();
            depDevices = this.profileDAO.getDEPDevices(request);
            count = this.profileDAO.getDEPDevicesCount();
            paginationResult.setData(depDevices);
        } catch (MobileDeviceManagementDAOException e) {
            String msg = "Could not fetch the DEP profiles.";
            log.error(msg, e);
            throw new ProfileConfigurationException(msg, e);
        } finally {
            IOSDAOFactory.closeConnection();
        }
        paginationResult.setRecordsFiltered(count);
        paginationResult.setRecordsTotal(count);
        return paginationResult;
    }

    @Override
    public DEPDevice getDEPDeviceByDeviceId(String id) throws ProfileConfigurationException {
        DEPDevice depDevice;
        try {
            IOSDAOFactory.getConnection();
            depDevice = this.profileDAO.getDEPDeviceByDeviceId(id);
        } catch (MobileDeviceManagementDAOException e) {
            String msg = "Could not fetch the DEP device with id:" + id;
            log.error(msg, e);
            throw new ProfileConfigurationException(msg, e);
        } finally {
            IOSDAOFactory.closeConnection();
        }
        return depDevice;
    }

    @Override
    public void updateDeviceUser(String username, String[] serials, boolean requireBasicAuth, boolean requireAgentInstall) throws
            ProfileConfigurationException {
        try {
            IOSDAOFactory.beginTransaction();
            for (String serial : serials) {
                this.profileDAO.updateDeviceUser(serial, username, requireBasicAuth, requireAgentInstall);
            }
            IOSDAOFactory.commitTransaction();
        } catch (MobileDeviceManagementDAOException e) {
            try {
                IOSDAOFactory.rollbackTransaction();
            } catch (MobileDeviceManagementDAOException e1) {
                log.warn("Error occurred while roll-backing the transaction", e);
            }
            throw new ProfileConfigurationException("Error occurred while adding the profile", e);
        } finally {
            IOSDAOFactory.closeConnection();
        }
    }

    @Override
    public void assignProfileToDevice(String uuid, String[] serialNumbers) throws
            ProfileConfigurationException {
        try {
            DEPProfile depProfile = getDEPProfile(uuid);
            if (depProfile != null && depProfile.getId() != null) {
                IOSDAOFactory.beginTransaction();
                for (String serial : serialNumbers) {
                    this.profileDAO.assignProfileToDevice(depProfile.getId(), serial);
                }
                IOSDAOFactory.commitTransaction();
            }
        } catch (MobileDeviceManagementDAOException e) {
            try {
                IOSDAOFactory.rollbackTransaction();
            } catch (MobileDeviceManagementDAOException e1) {
                log.warn("Error occurred while roll-backing the transaction", e);
            }
            throw new ProfileConfigurationException("Error occurred while adding the profile", e);
        } finally {
            IOSDAOFactory.closeConnection();
        }
    }

    @Override
    public void removeProfileToDeviceAssignment(String[] serialNumbers) throws
            ProfileConfigurationException {
        try {

            IOSDAOFactory.beginTransaction();
            for (String serial : serialNumbers) {
                this.profileDAO.removeProfileToDeviceAssignment(serial);
            }
            IOSDAOFactory.commitTransaction();
        } catch (MobileDeviceManagementDAOException e) {
            try {
                IOSDAOFactory.rollbackTransaction();
            } catch (MobileDeviceManagementDAOException e1) {
                log.warn("Error occurred while roll-backing the transaction", e);
            }
            throw new ProfileConfigurationException("Error occurred while adding the profile to device mapping", e);
        } finally {
            IOSDAOFactory.closeConnection();
        }
    }
}
