package com.hp.ucmdb.rest.uiserver.integrationstudio.controllers.sample;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/*
    This scenario is to run full sync and then delta sync of all jobs under inactive integration points.
*/
public class JobSyncScenarioSample {
    //the parameters you need to provide are serverIp, userName and password
    public static void main(String[] args) throws Exception {

        //get token for authentication
        String serverIp = " ucmdb-11-2-40.u.cms-demo.com " ;//input
        String userName = " admin " ;//input
        String password = " admin " ;//input
        String token = RestApiConnectionUtils.loginServer(serverIp, userName, password);//login server
        if(token == null || token.length() == 0){
            System.out.println( " Can not log in to the UCMDB server. Check your serverIp, userName or password! " );
            return;
        }
        System.out.println(token);

        //get details of all integration points
        String getResult = RestApiConnectionUtils.getAllIntegrationPoints(token, serverIp);
        JSONObject allIntegrationPoints = new JSONObject(getResult);
        if(allIntegrationPoints == null){
            System.out.println( " Can not get details of all integration points! " );
            return;
        }

        //get names of all inactive integration points
        List inactiveList = getAllInactiveIntegrationPoints(allIntegrationPoints);
        if(inactiveList.size() == 0){
            System.out.println( " No inactive integration point found! " );
            return;
        }
        System.out.println( " The list of inactive integration points is " + inactiveList.toString());

        System.out.println();
        System.out.println( " Now, start to full sync! " );

        //full sync all the jobs of inactive integration points
        for (String integration_name: inactiveList) {
            //activate an inactive integration point
            if(!activeIntegrationPoint(token, serverIp, integration_name)){
                System.out.println( " Failed to activate the " + integration_name + " integration point. " );
                inactiveList.remove(integration_name);// remove the integration point if activation failed
                continue;
            }

            //get all the job in this integration point
            List> jobList = getAllJobs(allIntegrationPoints, integration_name);

            if(jobList.size() > 0){
                syncAllJobs(jobList,token,serverIp,integration_name, " FULL " );// " FULL " means full sync
            }else{
                System.out.println( " No jobs found in the " + integration_name + " integration point. " );
            }
        }

        System.out.println();
        System.out.println( " Now, start to delta sync! " );

        //delta sync all the jobs of inactive
        for (String integration_name: inactiveList) {

            //get all the jobs in this integration point
            List> jobList = getAllJobs(allIntegrationPoints, integration_name);

            if(jobList.size() > 0){
                syncAllJobs(jobList,token,serverIp,integration_name, " DELTA " );// " DELTA " means delta sync
            }else{
                System.out.println( " No jobs found in the " + integration_name + " integration point. " );
            }
        }
        System.out.println( " Done! " );
    }

    //activate one inactive integration point
    private static boolean activeIntegrationPoint(String token, String serverIP, String integrationPoint_name)throws IOException, JSONException, NoSuchAlgorithmException, KeyManagementException, InterruptedException{

        String result = RestApiConnectionUtils.activateOrDeactivateIntegrationPoint(token, serverIP, integrationPoint_name, true);
        boolean tag = false;
        if(result != null && result.indexOf( " 200 " ) != -1){
        // waiting for the activating process done
            tag = waitingProcessEnd(3, token, serverIP, integrationPoint_name, null, 0);
        }
        if (!tag){
            System.out.println( " Failed to activate the " + integrationPoint_name + " integration point. " );
        }
        return tag;
    }

    // sync all jobs in one integration point
    /* there are four values for sync_type: PUSH_FULL / PUSH_DELTA / POPULATION_FULL / POPULATION_DELTA*/
    private static void syncAllJobs(List> jobList, String token, String serverIP, String integrationPoint_name, String sync_type)throws InterruptedException, JSONException, NoSuchAlgorithmException, KeyManagementException, IOException{
        for (Map map: jobList) {
            String jobCategory = map.get( " category " );

            // sync population jobs
            if( " POPULATION " .equals(jobCategory)){
                String job_name = map.get( " name " );

                //sync the job
                String operation_type = " POPULATION_ " + sync_type;
                System.out.println( " full population job syncing... " );
                String result = RestApiConnectionUtils.syncJob(token, serverIP, integrationPoint_name, job_name, operation_type);
                System.out.println( " the request of population " + sync_type + " sync is " + result);

                //waiting for the syncing process done
                if(!waitingProcessEnd(3, token, serverIP, integrationPoint_name, job_name, 1)){
                    System.out.println( " Can not get the sync job status! The job name is ( " + job_name + " ) and integration name is ( " + integrationPoint_name + " ) " );
                    continue;
                }
            }else if( " PUSH " .equals(jobCategory)){//sync push job
                String job_name = map.get( " name " );

                //sync the job
                String operation_type = " PUSH_ " + sync_type;
                System.out.println( " full push job syncing... " );
                String result = RestApiConnectionUtils.syncJob(token, serverIP, integrationPoint_name, job_name, operation_type);
                System.out.println( " the result of push " + sync_type + " sync is " + result);

                //waiting for the syncing process done
                if(!waitingProcessEnd(3, token, serverIP, integrationPoint_name, job_name, 1)){
                    System.out.println( " Can not get the sync job status! The job name is ( " + job_name + " ) and integration name is ( " + integrationPoint_name + " ) " );
                    continue;
                }

            }
        }
    }

    //waiting for the activating process or syncing process (interval in seconds)
    private static boolean waitingProcessEnd(int intervalSeconds, String token, String serverIP, String integrationPoint_name, String job_name, int job_category)throws JSONException,IOException{
        boolean loop = false;
        int count = 0;
        while (!loop){
            try{
                Thread.sleep(intervalSeconds*1000);
                count++;
                String printInfo = job_name == null ? " integration point name is " + integrationPoint_name : " integration point name is " + integrationPoint_name + " and job name is " + job_name;
                System.out.println( " Checking status. Attempt " + count + " ... " + " ( " + printInfo + " ) " );

                String status = job_name == null ? getIntegrationPointActiveStatus(token, serverIP, integrationPoint_name) : getJobStatus(token, serverIP, integrationPoint_name, job_name, job_category);
                System.out.println( " The status is " + status);
                if(status == null){
                    System.out.println( " Check the server connection! " );
                    break;
                }

                if( status.indexOf( " SUCCESS " ) != -1 || status.indexOf( " SUCESS " ) != -1){
                    System.out.println( " Checking over with successful! " );
                    System.out.println();
                    loop = true;
                    break;
                }
                if(count >= 20){
                    System.out.println( " Checking status failed. You have exceeded the maximum attempts allowed. " );
                    break;
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        return loop;
    }

    //get the integration point activation status
    private static String getIntegrationPointActiveStatus(String token, String serverIP, String integrationPoint_name)throws IOException, JSONException{
        //get the special integration point
        String integrationPointDetail = RestApiConnectionUtils.getSingleIntegrationPoint(token,serverIP,integrationPoint_name);

        //get special job in one integration point
        JSONObject integrationJson = new JSONObject(integrationPointDetail);
        String result = integrationJson.getBoolean( " enabled " ) ? " SUCCESS " : " DISABLE " ;
        return result;
    }


    //get the running job's status
    private static String getJobStatus(String token, String serverIP, String integrationPoint_name, String job_name, int job_category)throws IOException, JSONException{
        //get the specific integration point
        String integrationPointDetail = RestApiConnectionUtils.getSingleIntegrationPoint(token, serverIP, integrationPoint_name);

        if(integrationPointDetail != null){
            String status = null;
            if(job_category == 1)
                status = getPopulationJobStatus(new JSONObject(integrationPointDetail), job_name);//get statuses of population jobs
            if(job_category == 2)
                status = getPushJobStatus(new JSONObject(integrationPointDetail), job_name);//get statuses of push jobs
            if(status == null){
                System.out.println( " Failed to get statuses of jobs! " );
                return null;
            }
            return status;
        }
        return null;
    }

    //get statuses of population jobs
    private static String getPopulationJobStatus(JSONObject integrationDetail, String job_name)throws JSONException{
        if(integrationDetail != null && integrationDetail.has( " dataPopulationJobs " )){
            JSONArray populationJobList = integrationDetail.getJSONArray( " dataPopulationJobs " );
            for(int i = 0; i < populationJobList.length(); i++){
                JSONObject tmp = populationJobList.getJSONObject(i);
                if(tmp.getString( " displayID " ).equals(job_name));
                JSONObject statusJson = tmp.getJSONObject( " jobStatistics " );
                return statusJson.getString( " jobStatus " );
            }
        }
        return null;
    }

    //get statuses of push jobs
    private static String getPushJobStatus(JSONObject integrationDetail, String job_name)throws JSONException{
        if(integrationDetail != null && integrationDetail.has( " dataPushJobs " )){
            JSONArray pushJobList = integrationDetail.getJSONArray( " dataPushJobs " );
            for (int i = 0; i < pushJobList.length(); i++) {
                JSONObject tmp = pushJobList.getJSONObject(i);
                if(tmp.getString( " displayID " ).equals(job_name)){
                    String status = " UNKNOWN " ;
                    boolean enabled = integrationDetail.getBoolean( " enabled " );
                    if(!enabled){//disabled
                        status = " DISABLED " ;
                    }else {
                        JSONObject statusJson = tmp.getJSONObject( " jobRunCurrentStatus " );
                        if(statusJson != null && " RUNNING " .equals(statusJson.getString( " status " ))){//running
                            status = " RUNNING " ;
                        }else {//other status
                            statusJson = tmp.getJSONArray( " jobRunHistory " ).getJSONObject(0);
                            if(statusJson != null) status = statusJson.getString( " status " );
                        }
                    }
                    return status;
                }
            }
        }
        return null;
    }

    private static List getAllInactiveIntegrationPoints(JSONObject allIntegrationPoints) throws JSONException{
        List list = new ArrayList<>();
        if (allIntegrationPoints != null) {
            Iterator iter = allIntegrationPoints.keys();
            while (iter.hasNext()) {
                String integrationPoint = (String)iter.next();
                if(! " HistoryDataSource " .equals(integrationPoint) && ! " UCMDBDiscovery " .equals(integrationPoint)
                        && !allIntegrationPoints.getJSONObject(integrationPoint).getBoolean( " enabled " )){
                    list.add(integrationPoint);
                }
            }
        }
        return list;
    }

    private static List> getAllJobs(JSONObject allIntegrationPoints, String integrationPoint_name)throws JSONException{
        List> jobList = new ArrayList<>();
        JSONObject singleIntegration = allIntegrationPoints.getJSONObject(integrationPoint_name);
        if(singleIntegration == null) return null;

        //add population jobs
        JSONArray populationJobArray = singleIntegration.getJSONArray( " dataPopulationJobs " );
        for(int i = 0; i < populationJobArray.length(); i++){
            Map tmp = new HashMap<>();
            String jobName = populationJobArray.getJSONObject(i).getString( " displayID " );
            tmp.put( " name " ,jobName);
            tmp.put( " category " , " POPULATION " );
            jobList.add(tmp);
        }

        //add push jobs
        JSONArray pushJobArray = singleIntegration.getJSONArray( " dataPushJobs " );
        for(int i = 0; i < pushJobArray.length(); i++){
            Map tmp = new HashMap<>();
            String jobName = pushJobArray.getJSONObject(i).getString( " displayID " );
            tmp.put( " name " ,jobName);
            tmp.put( " category " , " PUSH " );
            jobList.add(tmp);
        }

        return jobList;
    }



}