package de.lcs.wep.service;

import de.lcs.wep.calendar.Constants;
import de.lcs.wep.calendar.Resource;
import de.lcs.wep.calendar.CalendarReader;

import de.lcs.wep.rest.WePClient;
import de.lcs.wep.rest.response.LabelInfo;
import de.lcs.wep.service.update.UpdateManager;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.xml.bind.JAXBException;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.*;

/**
 * A service that polls calendar data in a constant interval and updates related WeP-Displays when necessary.
 * When necessary means every time the content to be displayed on the WeP changes.
 * <p/>
 * Created by Sönke Greve on 30.10.2014.
 */
public class WePService {

    private static Logger logger = LogManager.getLogger(WePService.class);

    /**
     * Creates a #WePService instance using a persisted properties file
     *
     * @param props
     * @return
     */
    public static WePService fromProperties(Properties props) {
        WePService service = new WePService();
        String strInterval = props.getProperty("update.interval");
        String strUseAlias = props.getProperty("use.date.alias");
        String template = props.getProperty("template");

        long interval;
        try {
            interval = Long.valueOf(strInterval);
        } catch (Exception e) {
            logger.warn("Couldn't read inverval property. Using " + Constants.DEFAULT_UPDATE_INTERVAL + " milliseconds");
            interval = Constants.DEFAULT_UPDATE_INTERVAL;
        }
        service.setInterval(interval);

        boolean useAlias;
        try {
            useAlias = Boolean.parseBoolean(strUseAlias);
        } catch (Exception e) {
            logger.warn("Couldn't read inverval property. Using no date aliases");
            useAlias = false;
        }
        service.setUseAlias(useAlias);
        service.setTemplate(template);

        return service;
    }

    private long interval;
    private CalendarReader calendarReader;
    private WePClient client;
    private Timer timer;
    private TimerTask timerTask;
    private boolean useAlias;
    private String template;
    private UpdateManager updateManager;

    public WePService() {
        this.timerTask = createTimerTask();
        this.calendarReader = null;
        this.client = null;
        this.timer = null;
        this.updateManager = new UpdateManager();
        this.interval = 60000;
    }

    public void setInterval(long milliseconds) {
        this.interval = milliseconds;
    }

    public void setUseAlias(boolean useAlias) {
        this.useAlias = useAlias;
    }

    public void setCalendarReader(CalendarReader calendarReader) {
        this.calendarReader = calendarReader;
    }

    public void setClient(WePClient client) {
        this.client = client;
    }

    public void setTemplate(String template) {
        this.template = template;
    }

    public void start() {
        timer = new Timer("WeP Service Task");
        timer.scheduleAtFixedRate(timerTask, 0, interval);
    }

    public void stop() {
        timer.cancel();
        timer.purge();
    }

    private TimerTask createTimerTask() {
        TimerTask result = new TimerTask() {
            @Override
            public void run() {
                update();
            }
        };
        return result;
    }

    private void update() {

        try {
            logger.info("updating -------------------------------------------------");

            // update calendar data
            logger.info("reading calendars");
            Set<Resource> calendars = getCalendars();

            // get the available WePs
            logger.info("reading WeP states");
            List<LabelInfo> labelInfos = getLabelInfos();

            // update labels from WeP->tag->calendar
            logger.info("updating WePs");
            updateManager.update(calendars, labelInfos, this);

        } catch (Exception ex) {
            logger.error("Error in update cycle: " + ex.getMessage());
        }


    }

    private List<LabelInfo> getLabelInfos() {
        List<LabelInfo> labelInfos = null;
        try {
            labelInfos = client.getLabelInfos();
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return labelInfos;
    }

    private Set<Resource> getCalendars() {
        if (calendarReader != null) {
            try {
                calendarReader.update();
            } catch (GeneralSecurityException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        Set<Resource> result = calendarReader.getResources();
        return result;
    }

    public boolean getUseAlias() {
        return useAlias;
    }

    public String getTemplate() {
        return template;
    }

    public WePClient getClient() {
        return client;
    }
}
