package org.aegee.runanddine.pathfinder.groupbuilding;

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

import org.aegee.runanddine.BasePage;
import org.aegee.runanddine.RunAndDineApplication;
import org.aegee.runanddine.pathfinder.MainCourseSelector;
import org.aegee.runanddine.pathfinder.OptGroup;
import org.aegee.runanddine.registration.SingleRegistration;
import org.aegee.runanddine.runanddine.RunAndDine;
import org.aegee.runanddine.util.data.ModelNotExistingException;
import org.apache.wicket.Component;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.markup.html.IHeaderResponse;
import org.apache.wicket.markup.html.WebMarkupContainer;
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.markup.html.panel.ComponentFeedbackPanel;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.request.mapper.parameter.PageParameters;

public class GroupManager extends BasePage {

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

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

        // fetch id from the parameters
        final int id = parameters.get("id").toInt();

        add(new Behavior() {

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

        final WebMarkupContainer cont = new WebMarkupContainer("feedbackContainer") {

            @Override
            protected void onBeforeRender() {
                super.onBeforeRender();
                this.setVisible(this.hasFeedbackMessage());
            }
        };
        ComponentFeedbackPanel feedback = new ComponentFeedbackPanel("feedback", cont);
        cont.add(feedback);
        add(cont);

        List<OptGroup> opts = OptGroup.getAllSingleGroups(id);
        final List<OptGroupInfo> groups = new ArrayList<OptGroupInfo>(opts.size());
        for (OptGroup o : opts) {
            groups.add(new OptGroupInfo(o.getFirstParticipant(), o.getSecondParticipant()));
        }

        ListView<OptGroupInfo> list = new ListView<OptGroupInfo>("list", groups) {

            @Override
            protected void populateItem(ListItem<OptGroupInfo> item) {

                item.add(new Label("groupNo", Integer.toString(item.getIndex() + 1)).setOutputMarkupId(true));
                WebMarkupContainer cont1 = new WebMarkupContainer("cont1");
                cont1.add(new HiddenField("id1")).setOutputMarkupId(true);
                cont1.add(new HiddenField("key1", new Model<Integer>(item.getIndex()*2))).setOutputMarkupId(true);
                cont1.add(new TextField("firstName1")).setOutputMarkupId(true);
                cont1.add(new TextField("lastName1")).setOutputMarkupId(true);
                cont1.add(new TextField("street1"));
                cont1.add(new HiddenField("isKitchenAvailable1"));
                cont1.add(new HiddenField("address1"));
                if (item.getModelObject().isKitchenAvailable1) {
                    cont1.add(new AttributeAppender("class", " hasKitchen"));
                }
                item.add(cont1);

                WebMarkupContainer cont2 = new WebMarkupContainer("cont2");
                cont2.add(new HiddenField("id2")).setOutputMarkupId(true);
                cont2.add(new HiddenField("key2", new Model<Integer>(item.getIndex()*2+1))).setOutputMarkupId(true);
                cont2.add(new TextField("firstName2")).setOutputMarkupId(true);
                cont2.add(new TextField("lastName2")).setOutputMarkupId(true);
                cont2.add(new TextField("street2"));
                cont2.add(new HiddenField("address2"));
                cont2.add(new HiddenField("isKitchenAvailable2"));
                if (item.getModelObject().isKitchenAvailable2) {
                    cont2.add(new AttributeAppender("class", " hasKitchen"));
                }
                item.add(cont2);
                item.setModel(new CompoundPropertyModel<OptGroupInfo>(groups.get(item.getIndex())));
            }
        };
        Button button = new Button("button");
        final Form<OptGroupInfo> form = new Form<OptGroupInfo>("form") {

            @Override
            protected void onSubmit() {
                super.onSubmit();

                // delete all opt groups
                deleteSingleRegistration(id);
                // build new opt groups
                for (OptGroupInfo opt : groups) {
                    try {
                        int id1 = opt.getId1();
                        int id2 = opt.getId2();
                        SingleRegistration sr1 = SingleRegistration.OBJECTS.getById(id1);
                        SingleRegistration sr2 = SingleRegistration.OBJECTS.getById(id2);

                        if (sr1.isKitchenAvailable() || sr2.isKitchenAvailable()) {
                            OptGroup newOptGroup = new OptGroup(sr1, sr2);
                            newOptGroup.setRunAndDineId(id);
                            OptGroup.OBJECTS.save(newOptGroup);
                        } else {
                            cont.setVisible(true);
                            cont.error("There are groups without an available kitchen.");
                        }
                    } catch (ModelNotExistingException ex) {
                        // TODO: dont care?
                    }
                }
                if (!cont.hasErrorMessage()) {
                    setResponsePage(MainCourseSelector.class, new PageParameters().add("id", id));
                }
            }
        };
        form.add(button);
        form.add(list);
        add(form);
    }

    private static void deleteSingleRegistration(int id) {
        for (OptGroup o : OptGroup.OBJECTS.getAllByRunAndDineId(id)) {
            if (!o.isGroupRegistration()) {
                OptGroup.OBJECTS.delete(o);
            }
        }
    }
}

class OptGroupInfo implements Serializable {

    int id1;
    int id2;
    String firstName1;
    String firstName2;
    String lastName1;
    String lastName2;
    String street1;
    String street2;
    String address1;
    String address2;
    boolean isKitchenAvailable1;
    boolean isKitchenAvailable2;

    public OptGroupInfo(SingleRegistration part1, SingleRegistration part2) {
        this.firstName1 = part1.getFirstName();
        this.firstName2 = part2.getFirstName();
        this.lastName1 = part1.getLastName();
        this.lastName2 = part2.getLastName();
        this.id1 = part1.getId();
        this.id2 = part2.getId();
        this.isKitchenAvailable1 = part1.isKitchenAvailable();
        this.isKitchenAvailable2 = part2.isKitchenAvailable();
        this.street1 = part1.getStreetName() + " " + part1.getStreetNo();
        this.street2 = part2.getStreetName() + " " + part2.getStreetNo();
        this.address1 = this.street1 + " " + part1.getPostalCode() + " " + part1.getCity();
        this.address2 = this.street2 + " " + part2.getPostalCode() + " " + part2.getCity();
    }

    public int getId1() {
        return this.id1;
    }

    public int getId2() {
        return this.id2;
    }

    public void setId1(int id) {
        this.id1 = id;
    }

    public void setId2(int id) {
        this.id2 = id;
    }

    public String getFirstName1() {
        return this.firstName1;
    }

    public String getLastName1() {
        return this.lastName1;
    }

    public String getFirstName2() {
        return this.firstName2;
    }

    public String getLastName2() {
        return this.lastName2;
    }

    public void setFirstName1(String firstName) {
        this.firstName1 = firstName;
    }

    public void setLastName1(String lastName) {
        this.lastName1 = lastName;
    }

    public void setFirstName2(String firstName) {
        this.firstName2 = firstName;
    }

    public void setLastName2(String lastName) {
        this.lastName2 = lastName;
    }

    public String getName1() {
        return getFirstName1() + " " + getLastName1();
    }

    public String getName2() {
        return getFirstName2() + " " + getLastName2();
    }

    @Override
    public String toString() {
        return "[" + getId1() + " " + getFirstName1() + " " + getLastName1() + ", " + getId2() + " " + getFirstName2() + " " + getLastName2() + "]";
    }

    public boolean isIsKitchenAvailable1() {
        return isKitchenAvailable1;
    }

    public boolean isIsKitchenAvailable2() {
        return isKitchenAvailable2;
    }

    public void setIsKitchenAvailable1(boolean isKitchenAvailable1) {
        this.isKitchenAvailable1 = isKitchenAvailable1;
    }

    public void setIsKitchenAvailable2(boolean isKitchenAvailable2) {
        this.isKitchenAvailable2 = isKitchenAvailable2;
    }
}