package org.wso2.carbon.device.mgt.ios.util;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.base.MultitenantConstants;
import org.wso2.carbon.certificate.mgt.core.service.CertificateManagementService;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManagementException;
import org.wso2.carbon.device.mgt.core.app.mgt.ApplicationManagementProviderService;
import org.wso2.carbon.certificate.mgt.core.scep.SCEPManager;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.device.mgt.ios.apns.exception.APNSException;
import org.wso2.carbon.device.mgt.ios.apns.service.PushNotificationService;
import org.wso2.carbon.device.mgt.ios.core.exception.IOSEnrollmentException;
import org.wso2.carbon.device.mgt.ios.core.service.IOSEnrollmentService;
import org.wso2.carbon.device.mgt.ios.payload.exception.ProfileConfigurationException;
import org.wso2.carbon.device.mgt.mobile.impl.ios.enrollment.IOSEnrollmentTokenService;
import org.wso2.carbon.policy.mgt.common.PolicyManagementException;
import org.wso2.carbon.policy.mgt.core.PolicyManagerService;
import org.wso2.carbon.user.api.UserRealm;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.core.service.RealmService;
import org.wso2.carbon.device.mgt.mobile.impl.ios.profile.IOSProfileService;

public class IOSServiceUtils {

    public static final String HEADER_MDM_SIGNATURE = "Mdm-Signature";
    private static final Log log = LogFactory.getLog(IOSServiceUtils.class);

    public static IOSEnrollmentService getEnrollmentService() throws IOSEnrollmentException {

        PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
        IOSEnrollmentService enrollmentService = (IOSEnrollmentService)
                ctx.getOSGiService(IOSEnrollmentService.class, null);

        if (enrollmentService == null) {
            String msg = "IOSEnrollmentService is not initialized";
            log.error(msg);
            throw new IOSEnrollmentException(msg);
        }

        return enrollmentService;
    }

    public static IOSEnrollmentTokenService getEnrollmentTokenService() throws IOSEnrollmentException {

        PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
        IOSEnrollmentTokenService tokenService = (IOSEnrollmentTokenService)
                ctx.getOSGiService(IOSEnrollmentTokenService.class, null);

        if (tokenService == null) {
            String msg = "IOSEnrollmentTokenService is not initialized";
            log.error(msg);
            throw new IOSEnrollmentException(msg);
        }

        return tokenService;
    }

    public static IOSProfileService getProfileService() throws ProfileConfigurationException {

        PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
        IOSProfileService profileService = (IOSProfileService)
                ctx.getOSGiService(IOSProfileService.class, null);

        if (profileService == null) {
            String msg = "IOSProfileService is not initialized";
            log.error(msg);
            throw new ProfileConfigurationException(msg);
        }

        return profileService;
    }

    public static SCEPManager getSCEPManager() throws IOSEnrollmentException {

        PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
        SCEPManager scepManager = (SCEPManager) ctx.getOSGiService(SCEPManager.class, null);

        if (scepManager == null) {
            String msg = "SCEPManager is not initialized";
            log.error(msg);
            throw new IOSEnrollmentException(msg);
        }

        return scepManager;
    }

    public static CertificateManagementService getCertificateManagementService() throws IOSEnrollmentException {

        PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
        CertificateManagementService certificateManagementService = (CertificateManagementService)
                ctx.getOSGiService(CertificateManagementService.class, null);

        if (certificateManagementService == null) {
            String msg = "IOSEnrollmentService is not initialized";
            log.error(msg);
            throw new IOSEnrollmentException(msg);
        }

        return certificateManagementService;
    }

    public static DeviceManagementProviderService getDeviceManagementService() throws DeviceManagementException {

        PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
        DeviceManagementProviderService deviceManagementService = (DeviceManagementProviderService)
                ctx.getOSGiService(DeviceManagementProviderService.class, null);

        if (deviceManagementService == null) {
            String msg = "DeviceManagementService is not initialized";
            log.error(msg);
            throw new DeviceManagementException(msg);
        }

        return deviceManagementService;
    }

    public static ApplicationManagementProviderService getApplicationManagementService()
            throws ApplicationManagementException {

        PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
        ApplicationManagementProviderService applicationManagementService =
                (ApplicationManagementProviderService)
                        ctx.getOSGiService(ApplicationManagementProviderService.class, null);

        if (applicationManagementService == null) {
            String msg = "ApplicationManagementProviderService is not initialized";
            log.error(msg);
            throw new ApplicationManagementException(msg);
        }

        return applicationManagementService;
    }

    public static PolicyManagerService getPolicyManagerService() throws PolicyManagementException {

        PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
        PolicyManagerService policyManagerService = (PolicyManagerService)
                ctx.getOSGiService(PolicyManagerService.class, null);

        if (policyManagerService == null) {
            String msg = "PolicyManagerService is not initialized";
            log.error(msg);
            throw new PolicyManagementException(msg);
        }

        return policyManagerService;
    }

    public static PushNotificationService getPushNotificationService() throws APNSException {

        PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
        PushNotificationService pushNotificationService = (PushNotificationService)
                ctx.getOSGiService(PushNotificationService.class, null);

        if (pushNotificationService == null) {
            String msg = "PushNotificationService is not initialized";
            log.error(msg);
            throw new APNSException(msg);
        }

        return pushNotificationService;
    }

    public boolean authenticate(String username, String password, String tenantDomain) throws IOSEnrollmentException {

        try {
            PrivilegedCarbonContext.startTenantFlow();
            PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
            ctx.setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME);
            ctx.setTenantId(MultitenantConstants.SUPER_TENANT_ID);

            RealmService realmService = (RealmService) ctx.getOSGiService(RealmService.class, null);
            if (realmService == null) {
                String msg = "RealmService is not initialized";
                log.error(msg);
                throw new IOSEnrollmentException(msg);
            }

            int tenantId;
            if (tenantDomain == null || tenantDomain.isEmpty()) {
                tenantId = MultitenantConstants.SUPER_TENANT_ID;
            } else {
                tenantId = realmService.getTenantManager().getTenantId(tenantDomain);
                ctx.setTenantDomain(tenantDomain);
                ctx.setTenantId(tenantId);
            }

            if (tenantId == MultitenantConstants.INVALID_TENANT_ID) {
                log.error("Invalid tenant domain " + tenantDomain);
                return false;
            }

            UserRealm userRealm = realmService.getTenantUserRealm(tenantId);
            return userRealm.getUserStoreManager().authenticate(username, password);
        } catch (UserStoreException e) {
            String msg = "User store not initialized";
            log.error(msg);
            throw new IOSEnrollmentException(msg, e);
        } finally {
            PrivilegedCarbonContext.endTenantFlow();
        }
    }

    public static int getTenantID(String tenantDomain) throws IOSEnrollmentException {
        try {
            PrivilegedCarbonContext.startTenantFlow();
            PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
            ctx.setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME);
            ctx.setTenantId(MultitenantConstants.SUPER_TENANT_ID);

            RealmService realmService = (RealmService) ctx.getOSGiService(RealmService.class, null);
            if (realmService == null) {
                String msg = "RealmService is not initialized";
                log.error(msg);
                throw new IOSEnrollmentException(msg);
            }

            int tenantId;
            if (tenantDomain == null || tenantDomain.isEmpty()) {
                tenantId = MultitenantConstants.SUPER_TENANT_ID;
            } else {
                tenantId = realmService.getTenantManager().getTenantId(tenantDomain);
            }

            if (tenantId == MultitenantConstants.INVALID_TENANT_ID) {
                tenantId = MultitenantConstants.SUPER_TENANT_ID;
            }

            return tenantId;
        } catch (UserStoreException e) {
            String msg = "User store not initialized";
            log.error(msg);
            throw new IOSEnrollmentException(msg, e);
        } finally {
            PrivilegedCarbonContext.endTenantFlow();
        }
    }

}
