package usda.weru.weps.location;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.apache.log4j.Logger;
import org.jscience.geography.coordinates.LatLong;
import usda.weru.gis.GISData;
import usda.weru.gis.GISLookup;
import usda.weru.util.Caster;
import usda.weru.util.FireAllContext;
import usda.weru.util.LoadingContext;
import usda.weru.util.PropertyStackContext;
import usda.weru.weps.RunFileBean;

/**
 * Singleton
 * @author Joseph Levin <joelevin@weru.ksu.edu>
 */
public class LatLongSiteController implements PropertyChangeListener {

    private static final Logger LOGGER = Logger.getLogger(LatLongSiteController.class);
    private final RunFileBean c_bean;

    private LatLongSiteController(RunFileBean bean) {
        c_bean = bean;
        c_bean.addPropertyChangeListener(RunFileBean.PROP_SITE, this);
        c_bean.addPropertyChangeListener(RunFileBean.PROP_LATLONG, this);
    }

    /**
     * Constructs a new LatLongSiteController
     * @param bean
     */
    public static final void install(RunFileBean bean) {
        new LatLongSiteController(bean);
    }

    /**
     * fired iff either the site or location in the bean given during construction
     * changes
     * @param evt
     */
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
/**
                 * Note:  Assertions are not enabled.  These will be useless items
                 * unless assertions are enabled.  Thus, they will be commented out unless
                 * the user wishes to enable specific assertions (feed the virtual machine 
                 * the -ea argument).
                 */
//        assert evt.getSource() == c_bean;

        if (LoadingContext.isLoading(true) || FireAllContext.isInFireAll(true)) {
            return;
        }
        // call the correct internal handler for this change
        switch (evt.getPropertyName()) {
            case RunFileBean.PROP_SITE:
                siteChanged(c_bean.getSite());
                break;
            case RunFileBean.PROP_LATLONG:
                latlongChanged(c_bean.getLatLong());
                break;
        }
    }

    private void latlongChanged(final LatLong latlong) {

        if (PropertyStackContext.isPropertyOnStack(c_bean, RunFileBean.PROP_SITE, false)) {
            return;
        }
        try {
            GISLookup<Site<?>> lookup
                    = GISData.getInstance().<Site<?>>getLookup(Caster.<Class<Site<?>>>cast(Site.class));
            List<Site<?>> results = lookup.lookup(latlong);

            if (results.size() > 0) {
                Comparator<Site<?>> c = new Site.LevelComparator();
                Collections.sort(results, c);
                Site<?> mostDetail = results.get(results.size() - 1);
                c_bean.setSite(mostDetail);
            } else {
                c_bean.setSite(null);
            }

        } catch (Exception e) {
            //log the error
            e.printStackTrace();
        }

    }

    private void siteChanged(final Site<?> site) {

        if (site == null) {
            return;
        }

        if (PropertyStackContext.isPropertyOnStack(c_bean, RunFileBean.PROP_LATLONG, false)) {
            return;
        }

        c_bean.setLatLong(site.getLatLong());
    }
}
