package com.agilex.healthcare.schedulingmanager.mdws.translator ;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.cxf.common.util.StringUtils;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import com.agilex.healthcare.schedulingmanager.domain.SchedulingClinic;
import com.agilex.healthcare.schedulingmanager.domain.SchedulingClinics;
import com.agilex.healthcare.schedulingmanager.mdws.MdwsResponseException;
import com.agilex.healthcare.schedulingmanager.mdws.generatedwsdl.queryservice.TextArray;
import com.agilex.healthcare.utility.DateHelper;

@Service
@Scope(value = "singleton")
public class ClinicTranslator {

    private Log logger = LogFactory.getLog(ClinicTranslator.class);

    private static Map<String, String> serviceMap = new HashMap<String, String>() {{
        put("M", "MEDICINE");
        put("S", "SURGERY");
        put("P", "PSYCHIATRY");
        put("R", "REHAB MEDICINE");
        put("N", "NEUROLOGY");
        put("0", "NONE");
    }};

    public SchedulingClinics translate( final TextArray arr, final int start, final int end, final String facility, Map<String, String> specialtyMap) {
        logger.debug(String.format("Translating: start(%d), end(%d)", start, end));

        SchedulingClinics schedulingClinics = new SchedulingClinics( ) ;

        if( arr == null ) {
            throw new MdwsResponseException(
                    MdwsResponseException.UserMessages.INVALID_DATA_RETURNED , "TaggedHospitalLocationArray was null" ) ;
        }

        if( arr.getFault( ) != null ) {
            throw new MdwsResponseException( arr.getFault( ) ) ;
        }

        if( arr.getText() == null ) {
            return schedulingClinics;
        }

        return translateArrayOfStringTO(arr.getText().getString(), start, end, schedulingClinics, facility, specialtyMap) ;
    }

    private static final int ID = 0;
    private static final int CLINIC_NAME = 1;
    private static final int SERVICE = 2;
    private static final int SPECIALTY = 3;
    private static final int INACTIVATE = 4;
    private static final int REACTIVATE = 5;

    private SchedulingClinics translateArrayOfStringTO(final List<String> stringList, final int start, final int end, final SchedulingClinics schedulingClinics, final String facilityCode, final Map<String, String> specialtyMap) {
        if (null == stringList) {
            return schedulingClinics;
        }

        if (StringUtils.isEmpty(stringList)) {
            return schedulingClinics;
        }

        SchedulingSpecialtyBuilder builder = new SchedulingSpecialtyBuilder();
        builder.setFacilityCode(facilityCode);
        builder.setSchedulingClinics(schedulingClinics);
        for (int idx = start; idx < end; idx++) {
            String str = stringList.get(idx);
            if (!StringUtils.isEmpty(str)) {
                String[] fields = str.split("\\^");
                for (int i = 0; i < fields.length; i++) {
                    String value = fields[i];
                    switch (i) {
                        case ID:
                            builder.setId(value);
                            break;
                        case CLINIC_NAME:
                            builder.setClinicName(value);
                            break;
                        case SERVICE:
                            builder.setService(value);
                            break;
                        case SPECIALTY:
                            builder.setSpecialty(value);
                            break;
                        case INACTIVATE:
                            builder.setInactivate(value);
                            break;
                        case REACTIVATE:
                            builder.setReactivate(value);
                            break;
                    }
                }
            }
            builder.build();
        }
        return schedulingClinics;
    }

    private class SchedulingSpecialtyBuilder {
        private SchedulingClinics schedulingClinics;
        private String facilityCode;

        private String id;
        private String clinicName;
        private String service;
        private String specialty;
        private String inactivate;
        private String reactivate;

        public SchedulingSpecialtyBuilder setSchedulingClinics(final SchedulingClinics schedulingClinics) {
            this.schedulingClinics = schedulingClinics;
            return this;
        }
        
        public SchedulingSpecialtyBuilder setFacilityCode(final String facilityCode) {
            this.facilityCode = facilityCode;
            return this;
        }

        public SchedulingSpecialtyBuilder setId(final String id) {
            this.id = id;
            return this;
        }

        public SchedulingSpecialtyBuilder setClinicName(final String clinicName) {
            this.clinicName = clinicName;
            return this;
        }

        public SchedulingSpecialtyBuilder setService(final String service) {
            this.service = service;
            return this;
        }

        public SchedulingSpecialtyBuilder setSpecialty(final String specialty) {
            this.specialty = specialty;
            return this;
        }

        public SchedulingSpecialtyBuilder setInactivate(final String inactivate) {
            this.inactivate = inactivate;
            return this;
        }

        public SchedulingSpecialtyBuilder setReactivate(String reactivate) {
            this.reactivate = reactivate;
            return this;
        }

        public SchedulingSpecialtyBuilder build() {
            Date now = new Date();
            Date invalidateDate = DateHelper.parseVistaDate(inactivate);
            Date revalidateDate = DateHelper.parseVistaDate(reactivate);

            if (null == invalidateDate || (null != invalidateDate &&
                                           null != revalidateDate &&
                                           invalidateDate.before(revalidateDate) &&
                                           revalidateDate.before(now))) {
                if (StringUtils.isEmpty(service)) {
                    build("NONE");
                    return this;
                }

                if( !StringUtils.isEmpty(service)) {
                    build(mapService(service));
                }
            } else {
                if (logger.isDebugEnabled()) {
                    logger.debug(String.format("Skipped: facilityCode(%s), id(%s), service(%s), specialty(%s), clinicName(%s), inactivate(%s), reactivate(%s)\n",
                            value(facilityCode), value(id), value(service), value(specialty), value(clinicName), value(inactivate), value(reactivate)));
                }
            }
            resetInstanceFields();
            return this;
        }

        private String value(String val) {
            if (null == val) {
                return "null";
            }
            return val;
        }

        private SchedulingSpecialtyBuilder build(final String serviceOrSpecialty) {
            SchedulingClinic schedulingClinic = new SchedulingClinic();
            if (!StringUtils.isEmpty(id)) {
                schedulingClinic.setId(id);
            }

            if (!StringUtils.isEmpty(facilityCode)) {
                schedulingClinic.setFacilityCode(facilityCode);
            }

            if (!StringUtils.isEmpty(clinicName)) {
                schedulingClinic.setName(clinicName);
            }

            if (!StringUtils.isEmpty(service)) {
                schedulingClinic.setService(serviceOrSpecialty);
            }

            schedulingClinics.getSchedulingClinic().add(schedulingClinic);

            return this;
        }

        private String mapService(final String value) {
            if (StringUtils.isEmpty(value) || !serviceMap.containsKey(value)) {
                // Should never get here, but just in case
                logger.warn(String.format("The service '%s' is null or does not have a mapping. Using 'NONE'.", value));
                return "NONE";
            }
            return serviceMap.get(value);
        }
        
        public void resetInstanceFields() {
            this.id = null;
            this.clinicName = null;
            this.service = null;
            this.inactivate = null;
            this.reactivate = null;
        }
    }
}
