/*
 * Copyright (c) eHealth
 */

package be.fgov.ehealth.technicalconnector.tests.beid.tlv;

import be.ehealth.technicalconnector.enumeration.Charset;
import be.ehealth.technicalconnector.utils.ConnectorIOUtils;
import be.ehealth.technicalconnector.utils.MarshallerHelper;
import be.fedict.commons.eid.client.FileType;
import be.fgov.ehealth.technicalconnector.tests.beid.domain.testcard.DoctypeType;
import be.fgov.ehealth.technicalconnector.tests.beid.domain.testcard.Eid;
import be.fgov.ehealth.technicalconnector.tests.beid.domain.testcard.GenderType;
import be.fgov.ehealth.technicalconnector.tests.beid.domain.testcard.SpecType;
import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Locale;

/**
 * @author EHP
 */
public class XmlEidViewerTLVFileGenerator implements TLVFileGenerator {

    private static final Logger LOG = LoggerFactory.getLogger(XmlEidViewerTLVFileGenerator.class);

    public static final Locale DUTCH = new Locale("nl", "BE");

    private static MarshallerHelper<Eid, Eid> helper = new MarshallerHelper<Eid, Eid>(Eid.class, Eid.class);

    public byte[] generate(FileType fileType, String location) {
        try {
            Eid eid = helper.toObject(ConnectorIOUtils.getResourceAsStream(location));
            switch (fileType) {
                case Identity:
                    return toIdentity(eid);
                case Address:
                    return toAddress(eid);
                case Photo:
                    return eid.getIdentity().getPhoto();
                default:
                    throw new IllegalArgumentException("Unsupported fileType [" + fileType + "]");
            }
        } catch (Exception e) {
            LOG.error("Unable to generate content {}", e.getMessage());
        }
        return null;
    }

    public static byte[] toAddress(Eid eid) {
        ByteArrayOutputStream baos = null;
        try {
            baos = new ByteArrayOutputStream();
            writeTLV(1, eid.getAddress().getStreetandnumber().getBytes(Charset.UTF_8.getName()), baos);
            writeTLV(2, eid.getAddress().getZip().getBytes(Charset.UTF_8.getName()), baos);
            writeTLV(3, eid.getAddress().getMunicipality().getBytes(Charset.UTF_8.getName()), baos);
            return baos.toByteArray();
        } catch (Exception e) {
            throw new IllegalArgumentException(e);
        } finally {
            ConnectorIOUtils.closeQuietly(baos);
        }
    }

    public static byte[] toIdentity(Eid eid) {
        ByteArrayOutputStream baos = null;
        try {
            baos = new ByteArrayOutputStream();
            writeTLV(1, eid.getCard().getCardnumber().getBytes(Charset.UTF_8.getName()), baos);
            writeTLV(2, eid.getCard().getChipnumber(), baos);
            writeTLV(3, convert(eid.getCard().getValiditydatebegin(), "dd.MM.yyyy"), baos);
            writeTLV(4, convert(eid.getCard().getValiditydateend(), "dd.MM.yyyy"), baos);
            writeTLV(5, eid.getCard().getDeliverymunicipality().toString().getBytes(Charset.UTF_8.getName()), baos);
            writeTLV(6, eid.getIdentity().getNationalnumber().getBytes(Charset.UTF_8.getName()), baos);
            writeTLV(7, eid.getIdentity().getName().getBytes(Charset.UTF_8.getName()), baos);
            writeTLV(8, eid.getIdentity().getFirstname().getBytes(Charset.UTF_8.getName()), baos);
            writeTLV(9, eid.getIdentity().getMiddlenames().getBytes(Charset.UTF_8.getName()), baos);
            writeTLV(10, eid.getIdentity().getNationality().getBytes(Charset.UTF_8.getName()), baos);
            writeTLV(11, eid.getIdentity().getPlaceofbirth().getBytes(Charset.UTF_8.getName()), baos);
            writeTLV(12, convert(eid.getIdentity().getDateofbirth(), "dd.MMM.yyyy"), baos);
            writeTLV(13, convert(eid.getIdentity().getGender()), baos);
            if (StringUtils.isNotBlank(eid.getIdentity().getNoblecondition())) {
                writeTLV(14, eid.getIdentity().getNoblecondition().getBytes(Charset.UTF_8.getName()), baos);
            }
            writeTLV(15, convertDocumentType(eid.getCard().getDocumenttype()), baos);
            writeTLV(16, convertSpecialStatus(eid.getIdentity().getSpecialstatus()), baos);
            return baos.toByteArray();
        } catch (Exception e) {
            throw new IllegalArgumentException(e);
        } finally {
            ConnectorIOUtils.closeQuietly(baos);
        }
    }

    private static byte[] convertSpecialStatus(SpecType specialstatus) {
        switch (specialstatus) {
            case NO_STATUS:
                return "0".getBytes();
            case WHITE_CANE:
                return "1".getBytes();
            case EXTENDED_MINORITY:
                return "2".getBytes();
            case WHITE_CANE_EXTENDED_MINORITY:
                return "3".getBytes();
            case YELLOW_CANE:
                return "4".getBytes();
            case YELLOW_CANE_EXTENDED_MINORITY:
                return "5".getBytes();
            default:
                throw new IllegalArgumentException("Unsupported SpecialStatus [" + specialstatus + "]");
        }
    }

    private static void writeTLV(int idx, byte[] content, OutputStream os) throws IOException {
        os.write(idx);
        os.write(content.length);
        os.write(content);
    }

    private static byte[] convert(String cal, String targetFormat) throws Exception {
        SimpleDateFormat source = new SimpleDateFormat("yyyyMMdd");
        SimpleDateFormat target = new SimpleDateFormat(targetFormat, DUTCH);
        return target.format(source.parse(cal)).toUpperCase().getBytes(Charset.UTF_8.getName());
    }

    private static byte[] convert(GenderType gender) {
        switch (gender) {
            case MALE:
                return "M".getBytes();
            case FEMALE:
                return "F".getBytes();
            default:
                throw new IllegalArgumentException("Unsupported gender [" + gender + "]");
        }
    }

    private static byte[] convertDocumentType(DoctypeType docType) {
        switch (docType) {
            case BELGIAN_CITIZEN:
                return "1".getBytes();
            case KIDS_CARD:
                return "6".getBytes();
            case BOOTSTRAP_CARD:
                return "7".getBytes();
            case HABILITATION_CARD:
                return "8".getBytes();
            case FOREIGNER_A:
                return "11".getBytes();
            case FOREIGNER_B:
                return "12".getBytes();
            case FOREIGNER_C:
                return "13".getBytes();
            case FOREIGNER_D:
                return "14".getBytes();
            case FOREIGNER_E:
                return "15".getBytes();
            case FOREIGNER_E_PLUS:
                return "16".getBytes();
            case FOREIGNER_F:
                return "17".getBytes();
            case FOREIGNER_F_PLUS:
                return "18".getBytes();
            case EUROPEAN_BLUE_CARD_H:
                return "19".getBytes();
            default:
                throw new IllegalArgumentException("Unsupported gender [" + docType + "]");
        }
    }


}
