package org.aegee.runanddine.pathfinder;

import java.io.Serializable;
import java.util.List;

import org.aegee.runanddine.BasePage;
import org.aegee.runanddine.RunAndDineApplication;
import org.aegee.runanddine.pathfinder.assignmentbuilding.OptimizationOverviewPage;
import org.aegee.runanddine.runanddine.RunAndDine;
import org.aegee.runanddine.status.RunAndDineStatus;
import org.aegee.runanddine.util.data.ModelNotExistingException;
import org.apache.wicket.Component;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.markup.html.IHeaderResponse;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.HiddenField;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.request.resource.JavaScriptResourceReference;
import org.apache.wicket.request.resource.ResourceReference;

/**
 * Page do display the DistanceMatrix for a RunAndDine
 */
public class DistanceMatrixPage extends BasePage {

    public DistanceMatrixPage(RunAndDine event) {
        this(new PageParameters().add("id", event.getId()));
    }

    public DistanceMatrixPage(PageParameters parameters) {
        super(parameters);

        // add Javascript and call initialize()
        add(new Behavior() {

            private final ResourceReference DMJS = new JavaScriptResourceReference(DistanceMatrixPage.class, "DistanceMatrix.js");

            @Override
            public void renderHead(Component component, IHeaderResponse response) {
                response.renderJavaScriptReference("http://maps.googleapis.com/maps/api/js?key="+RunAndDineApplication.GOOGLE_KEY+"&sensor=false");
                response.renderJavaScriptReference(DMJS);
                response.renderOnDomReadyJavaScript("initialize()"); //on Load
            }
        });

        // fetch id from the parameters
        final int id = parameters.get("id").toInt();
        final List<OptGroup> groups = OptGroup.OBJECTS.getAllByRunAndDineId(id);

        Addresses addr = new Addresses(groups);
        HiddenField<String> addrText = new HiddenField<String>("addresses", new PropertyModel(addr, "addresses"));
        add(addrText);

        // form for the distanceMatrix   
        final DistanceMatrix distanceMatrix = getMatrixOrNew(id, groups.size());
        Form<DistanceMatrix> form = new Form<DistanceMatrix>("form") {

            @Override
            protected void onSubmit() {
                super.onSubmit();
                DistanceMatrixManager.getInstance().save(distanceMatrix);
                RunAndDineStatus.setStatusInformation(id, DistanceMatrixPage.class, "Distance Matrix saved.");
                try {
                    setResponsePage(new OptimizationOverviewPage(RunAndDine.OBJECTS.getById(id)));
                } catch (ModelNotExistingException e) {
                    // this should not happen -- so do not care
                }
            }
        };
        
        Button save = new Button("save");

        // Initialize DistanceMatrix (Table)
        ListView<OptGroup> head = new ListView<OptGroup>("head", groups) {

            @Override
            protected void populateItem(ListItem<OptGroup> item) {
                item.add(new Label("destinationAddr", item.getModelObject().getKitchen()));
                item.add(new HiddenField("destinationId", new PropertyModel(item.getModelObject(), "id")).setMarkupId("destinationId" + item.getIndex()));
            }
        };

        ListView<OptGroup> head2 = new ListView<OptGroup>("head2", groups) {

            @Override
            protected void populateItem(ListItem<OptGroup> item) {
                final int rowNumber = item.getIndex();
                item.add(new Label("originAddr", item.getModelObject().getKitchen()));
                item.add(new HiddenField("originId", new PropertyModel(item.getModelObject(), "id")).setMarkupId("originId" + item.getIndex()));
                item.add(new ListView<OptGroup>("placeholder", groups) {

                    @Override
                    protected void populateItem(ListItem<OptGroup> item) {
                        item.setMarkupId("element-" + rowNumber + "-" + item.getIndex());
                        DistanceMatrixEntry entry = distanceMatrix.getEntry(rowNumber, item.getIndex());
                        item.add(new HiddenField("id1", new PropertyModel(entry, "id1")));
                        item.add(new HiddenField("id2", new PropertyModel(entry, "id2")));
                        item.add(new TextField("distance", new PropertyModel(entry, "distance")));
                        item.add(new TextField("duration", new PropertyModel(entry, "duration")));
                    }
                });
            }
        };

        form.add(head);
        form.add(head2);
        form.add(save);
        add(form);
    }

    /**
     * Get DistanceMatrix for RunAndDine if one exists,
     * otherwise create new one
     * @param id ID of RunAndDine the DistanceMatrix is related to
     * @param size Size of the DistanceMatrix (if new one is created)
     * @return 
     */
    private static DistanceMatrix getMatrixOrNew(int id, int size) {
        try {
            return DistanceMatrixManager.getInstance().getByRunAndDineId(id);
        } catch (ModelNotExistingException e) {
            DistanceMatrix matrix = new DistanceMatrix(size);
            matrix.setRunAndDineId(id);
            return matrix;
        }
    }
}

/**
 * Concatenates a list of addresses in a string
 * @author Sebastian
 */
class Addresses implements Serializable {

    private String addresses;

    Addresses(List<OptGroup> list) {
        StringBuilder sb = new StringBuilder();
        for (OptGroup group : list) {
            sb.append(String.format("%s %s %s|", group.getKitchen(), group.getPostalCode(), group.getCity()));
        }
        if (!list.isEmpty()) {
            sb.deleteCharAt(sb.length() - 1);
        }
        addresses = sb.toString();
    }

    public String getAdresses() {
        return addresses;
    }
}