package com.agilex.healthcare.schedulingmanager.datalayer;

import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.ObjectWriter;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;

import com.agilex.healthcare.schedulingmanager.datalayer.fork.ProcessClinicsWithSpecialtiesTask;
import com.agilex.healthcare.schedulingmanager.datalayer.fork.ProcessClinicsWithSpecialtiesTaskRunner;
import com.agilex.healthcare.schedulingmanager.domain.SchedulingClinic;
import com.agilex.healthcare.schedulingmanager.domain.SchedulingClinics;
import com.agilex.healthcare.schedulingmanager.domain.SchedulingSpecialties;
import com.agilex.healthcare.schedulingmanager.domain.SchedulingSpecialty;
import com.agilex.healthcare.schedulingmanager.mdws.MdwsClinicSpecialtyHelper;
import com.agilex.healthcare.schedulingmanager.mdws.MdwsQueryDataLayer;
import com.agilex.healthcare.schedulingmanager.mdws.MdwsResponseException;
import com.agilex.healthcare.schedulingmanager.mdws.MdwsResponseValidator;
import com.agilex.healthcare.schedulingmanager.mdws.connection.MdwsConfiguration;
import com.agilex.healthcare.schedulingmanager.mdws.connection.QueryConnection;
import com.agilex.healthcare.schedulingmanager.mdws.generatedwsdl.queryservice.TextArray;

public class ToolsDataLayerMdws extends MdwsQueryDataLayer implements ToolsDataLayer, BeanFactoryAware {
    private final Log logger = LogFactory.getLog(ToolsDataLayerMdws.class);

    private static final String FILE   = "44";
    private static final String FIELDS = ".01;9;9.5;2505;2506";
    private static final String FLAGS  = "IP";
    private static final String SCREEN = "I $P(^(0),\"^\",3)=\"C\"";

    private BeanFactory beanFactory;

    @Resource
    private MdwsClinicSpecialtyHelper mdwsClinicSpecialtyHelper;

    @Resource
    private ProcessClinicsWithSpecialtiesTaskRunner processClinicsWithSpecialtiesTaskRunner;

    public ToolsDataLayerMdws(MdwsConfiguration mdwsConfiguration) {
        super(mdwsConfiguration);
    }

    @Override
    public SchedulingClinics getClinicsWithSpecialties(String siteCode) {
        logger.debug("Fetch Clinics and specialties");

        QueryConnection authenticatedSite = super.getAuthenticatedConnection(siteCode);
        TextArray textArray;
		try {
			textArray = authenticatedSite.getPort().ddrLister(FILE, "", FIELDS, FLAGS, "", "", "", "", SCREEN, "");
		} catch (Throwable t) {
			throw new MdwsResponseException(MdwsResponseException.UserMessages.CONNECTION_ERROR, t.getMessage());
		}
        MdwsResponseValidator.validateMdwsObject(textArray);

        if (logger.isDebugEnabled()) {
            ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
            try {
                String json = ow.writeValueAsString(textArray);
                logger.debug(json);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


        long start = System.currentTimeMillis();
        Map<String, String> clinicSpecialtyMap = mdwsClinicSpecialtyHelper.getSpecialtyMap(siteCode);
        ProcessClinicsWithSpecialtiesTask task = beanFactory.getBean("processClinicsWithSpecialtiesTask", ProcessClinicsWithSpecialtiesTask.class);
        SchedulingClinics schedulingClinics = processClinicsWithSpecialtiesTaskRunner.runJob(task, textArray, clinicSpecialtyMap, siteCode);
        long interval = System.currentTimeMillis() - start;

        if (null != schedulingClinics) {
            if (logger.isDebugEnabled()) {
                logger.debug(String.format("Total processing time (milliseconds): %d", interval));
                for (SchedulingClinic schedulingClinic : schedulingClinics) {
                    logger.debug(String.format("\t%s clinic\n", schedulingClinic.getName()));
                }
            }
        }
        

        // Sort clinics
        Collections.sort(schedulingClinics, new SchedulingClinicComparator());
        
        return schedulingClinics;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    private static class SchedulingSpecialtyComparator implements Comparator<SchedulingSpecialty> {

        @Override
        public int compare(SchedulingSpecialty schedulingSpecialty, SchedulingSpecialty schedulingSpecialty2) {
            return schedulingSpecialty.getName().compareTo(schedulingSpecialty2.getName());
        }
    }

    private static class SchedulingClinicComparator implements Comparator<SchedulingClinic> {

        @Override
        public int compare(SchedulingClinic schedulingClinic, SchedulingClinic schedulingClinic2) {
            return schedulingClinic.getName().compareTo(schedulingClinic2.getName());
        }
    }
}
