package org.aegee.runanddine.pathfinder.assignmentbuilding;

import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.aegee.runanddine.BasePage;
import org.aegee.runanddine.RunAndDineApplication;
import org.aegee.runanddine.information.InformationMailEditor;
import org.aegee.runanddine.pathfinder.Course;
import org.aegee.runanddine.pathfinder.OptGroup;
import org.aegee.runanddine.runanddine.RunAndDine;
import org.apache.wicket.Component;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.feedback.FeedbackMessage;
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.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.ComponentFeedbackPanel;
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 to display and edit course assignments for optimized groups
 */
public class GroupsAndAssignmentEditor extends BasePage {

    final Map<Integer, OptGroup> map;
    final List<OptGroup> groups;
    final WebMarkupContainer cont;

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

    public GroupsAndAssignmentEditor(final PageParameters parameters) {
        super(parameters);

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

        // add Javascript
        add(new Behavior() {
            private final ResourceReference GAAJS = new JavaScriptResourceReference(GroupsAndAssignmentEditor.class, "GroupsAndAssignmentEditor.js");

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

        groups = OptGroup.OBJECTS.getAllByRunAndDineId(id);
        map = new TreeMap<Integer, OptGroup>();

        for (OptGroup group : groups) {
            map.put(group.getId(), group);
        }

        ListView<OptGroup> list = new ListView<OptGroup>("list", groups) {
            @Override
            protected void populateItem(ListItem<OptGroup> item) {
                OptGroup group = item.getModelObject();
                item.setOutputMarkupId(true);

                WebMarkupContainer td1 = new WebMarkupContainer("td1");
                WebMarkupContainer td2 = new WebMarkupContainer("td2");
                WebMarkupContainer td3 = new WebMarkupContainer("td3");
                OptGroup group1 = map.get(group.getOtherId1());
                OptGroup group2 = map.get(group.getOtherId2());

                if (group.getCourse() == Course.HORS_DOEUVRE) {

                    td1.add(new HiddenField<Integer>("id1", new PropertyModel(group, "id")));
                    td1.add(new Label("name1", new PropertyModel(group, "namesAndAbstractId")));
                    td1.add(new HiddenField<Integer>("course1", new PropertyModel(group, "course")));
                    td1.add(new Label("kitchen1", new PropertyModel(group, "kitchen")));
                    td1.add(new HiddenField<String>("address1", new PropertyModel(group, "address")));
                    td1.add(new AttributeAppender("class", " self"));
                    td1.add(new HiddenField<Integer>("key1", new PropertyModel<Integer>(group, "abstractId")));

                    if (group.getOtherCourse1() == Course.MAIN) {
                        td2.add(new HiddenField<Integer>("id2", new PropertyModel(group, "otherId1")));
                        td2.add(new HiddenField<Integer>("course2", new PropertyModel(group, "otherCourse1")));
                        td2.add(new Label("name2", new PropertyModel(group1, "namesAndAbstractId")));
                        td2.add(new Label("kitchen2", new PropertyModel(group1, "kitchen")));
                        td2.add(new HiddenField<String>("address2", new PropertyModel(group1, "address")));
                        td2.add(new HiddenField<Integer>("key2", new PropertyModel<Integer>(group1, "abstractId")));

                        td3.add(new HiddenField<Integer>("id3", new PropertyModel(group, "otherId2")));
                        td3.add(new HiddenField<Integer>("course3", new PropertyModel(group, "otherCourse2")));
                        td3.add(new Label("name3", new PropertyModel(group2, "namesAndAbstractId")));
                        td3.add(new Label("kitchen3", new PropertyModel(group2, "kitchen")));
                        td3.add(new HiddenField<String>("address3", new PropertyModel(group2, "address")));
                        td3.add(new HiddenField<Integer>("key3", new PropertyModel<Integer>(group2, "abstractId")));
                    } else {
                        td3.add(new HiddenField<String>("id3", new PropertyModel(group, "otherId1")));
                        td3.add(new HiddenField<Integer>("course3", new PropertyModel(group, "otherCourse1")));
                        td3.add(new Label("name3", new PropertyModel(group1, "namesAndAbstractId")));
                        td3.add(new Label("kitchen3", new PropertyModel(group1, "kitchen")));
                        td3.add(new HiddenField<String>("address3", new PropertyModel(group1, "address")));
                        td3.add(new HiddenField<Integer>("key3", new PropertyModel<Integer>(group1, "abstractId")));

                        td2.add(new HiddenField<Integer>("id2", new PropertyModel(group, "otherId2")));
                        td2.add(new HiddenField<Integer>("course2", new PropertyModel(group, "otherCourse2")));
                        td2.add(new Label("name2", new PropertyModel(group2, "namesAndAbstractId")));
                        td2.add(new Label("kitchen2", new PropertyModel(group2, "kitchen")));
                        td2.add(new HiddenField<String>("address2", new PropertyModel(group2, "address")));
                        td2.add(new HiddenField<Integer>("key2", new PropertyModel<Integer>(group2, "abstractId")));
                    }
                } else if (group.getCourse() == Course.MAIN) {

                    td2.add(new HiddenField<Integer>("id2", new PropertyModel(group, "id")));
                    td2.add(new HiddenField<Integer>("course2", new PropertyModel(group, "course")));
                    td2.add(new Label("name2", new PropertyModel(group, "namesAndAbstractId")));
                    td2.add(new Label("kitchen2", new PropertyModel(group, "kitchen")));
                    td2.add(new HiddenField<String>("address2", new PropertyModel(group, "address")));
                    td2.add(new HiddenField<Integer>("key2", new PropertyModel<Integer>(group, "abstractId")));
                    td2.add(new AttributeAppender("class", " self"));

                    if (group.getOtherCourse1() == Course.HORS_DOEUVRE) {
                        td1.add(new HiddenField<Integer>("id1", new PropertyModel(group, "otherId1")));
                        td1.add(new HiddenField<Integer>("course1", new PropertyModel(group, "otherCourse1")));
                        td1.add(new Label("name1", new PropertyModel(group1, "namesAndAbstractId")));
                        td1.add(new Label("kitchen1", new PropertyModel(group1, "kitchen")));
                        td1.add(new HiddenField<String>("address1", new PropertyModel(group1, "address")));
                        td1.add(new HiddenField<Integer>("key1", new PropertyModel<Integer>(group1, "abstractId")));

                        td3.add(new HiddenField<Integer>("id3", new PropertyModel(group, "otherId2")));
                        td3.add(new HiddenField<Integer>("course3", new PropertyModel(group, "otherCourse2")));
                        td3.add(new Label("name3", new PropertyModel(group2, "namesAndAbstractId")));
                        td3.add(new Label("kitchen3", new PropertyModel(group2, "kitchen")));
                        td3.add(new HiddenField<String>("address3", new PropertyModel(group2, "address")));
                        td3.add(new HiddenField<Integer>("key3", new PropertyModel<Integer>(group2, "abstractId")));
                    } else {
                        td3.add(new HiddenField<Integer>("id3", new PropertyModel(group, "otherId1")));
                        td3.add(new HiddenField<Integer>("course3", new PropertyModel(group, "otherCourse1")));
                        td3.add(new Label("name3", new PropertyModel(group1, "namesAndAbstractId")));
                        td3.add(new Label("kitchen3", new PropertyModel(group1, "kitchen")));
                        td3.add(new HiddenField<String>("address3", new PropertyModel(group1, "address")));
                        td3.add(new HiddenField<Integer>("key3", new PropertyModel<Integer>(group1, "abstractId")));

                        td1.add(new HiddenField<Integer>("id1", new PropertyModel(group, "otherId2")));
                        td1.add(new HiddenField<Integer>("course1", new PropertyModel(group, "otherCourse2")));
                        td1.add(new Label("name1", new PropertyModel(group2, "namesAndAbstractId")));
                        td1.add(new Label("kitchen1", new PropertyModel(group2, "kitchen")));
                        td1.add(new HiddenField<String>("address1", new PropertyModel(group2, "address")));
                        td1.add(new HiddenField<Integer>("key1", new PropertyModel<Integer>(group2, "abstractId")));
                    }
                } else {
                    td3.add(new HiddenField<Integer>("id3", new PropertyModel(group, "id")));
                    td3.add(new HiddenField<Integer>("course3", new PropertyModel(group, "course")));
                    td3.add(new Label("name3", new PropertyModel(group, "namesAndAbstractId")));
                    td3.add(new AttributeAppender("class", " self"));
                    td3.add(new Label("kitchen3", new PropertyModel(group, "kitchen")));
                    td3.add(new HiddenField<String>("address3", new PropertyModel(group, "address")));
                    td3.add(new HiddenField<Integer>("key3", new PropertyModel<Integer>(group, "abstractId")));

                    if (group.getOtherCourse1() == Course.HORS_DOEUVRE) {
                        td1.add(new HiddenField<Integer>("id1", new PropertyModel(group, "otherId1")));
                        td1.add(new HiddenField<Integer>("course1", new PropertyModel(group, "otherCourse1")));
                        td1.add(new Label("name1", new PropertyModel(group1, "namesAndAbstractId")));
                        td1.add(new Label("kitchen1", new PropertyModel(group1, "kitchen")));
                        td1.add(new HiddenField<String>("address1", new PropertyModel(group1, "address")));
                        td1.add(new HiddenField<Integer>("key1", new PropertyModel<Integer>(group1, "abstractId")));

                        td2.add(new HiddenField<Integer>("id2", new PropertyModel(group, "otherId2")));
                        td2.add(new HiddenField<Integer>("course2", new PropertyModel(group, "otherCourse2")));
                        td2.add(new Label("name2", new PropertyModel(group2, "namesAndAbstractId")));
                        td2.add(new Label("kitchen2", new PropertyModel(group2, "kitchen")));
                        td2.add(new HiddenField<String>("address2", new PropertyModel(group2, "address")));
                        td2.add(new HiddenField<Integer>("key2", new PropertyModel<Integer>(group2, "abstractId")));
                    } else {
                        td2.add(new HiddenField<Integer>("id2", new PropertyModel(group, "otherId1")));
                        td2.add(new HiddenField<Integer>("course2", new PropertyModel(group, "otherCourse1")));
                        td2.add(new Label("name2", new PropertyModel(group1, "namesAndAbstractId")));
                        td2.add(new Label("kitchen2", new PropertyModel(group1, "kitchen")));
                        td2.add(new HiddenField<String>("address2", new PropertyModel(group1, "address")));
                        td2.add(new HiddenField<Integer>("key2", new PropertyModel<Integer>(group1, "abstractId")));

                        td1.add(new HiddenField<Integer>("id1", new PropertyModel(group, "otherId2")));
                        td1.add(new HiddenField<Integer>("course1", new PropertyModel(group, "otherCourse2")));
                        td1.add(new Label("name1", new PropertyModel(group2, "namesAndAbstractId")));
                        td1.add(new Label("kitchen1", new PropertyModel(group2, "kitchen")));
                        td1.add(new HiddenField<String>("address1", new PropertyModel(group2, "address")));
                        td1.add(new HiddenField<Integer>("key1", new PropertyModel<Integer>(group2, "abstractId")));
                    }
                }
                item.add(td1.setMarkupId("1"));
                item.add(td2.setMarkupId("2"));
                item.add(td3.setMarkupId("3"));
            }
        };

        cont = new WebMarkupContainer("error") {
            @Override
            protected void onBeforeRender() {
                super.onBeforeRender();
                this.setVisible(this.hasFeedbackMessage());
            }
        };


        Button save = new Button("save") {
            public void onSubmit() {
                save();
            }
        };

        Button button = new Button("button") {
            public void onSubmit() {
                save();
                for (FeedbackMessage msg : cont.getFeedbackMessages()) {
                    msg.markRendered();
                }
                setResponsePage(InformationMailEditor.class, parameters);
            }
        };

        final Form<OptGroup> form = new Form<OptGroup>("form");
        cont.add(new ComponentFeedbackPanel("feedback", cont));
        add(cont);
        form.add(button);
        form.add(save);
        form.add(list);
        add(form);
    }

    /**
     * Save assignments persistently
     */
    private void save() {
        // set the new guests
        for (OptGroup group : groups) {
            for (OptGroup temp : groups) {
                if (group.getId() == temp.getOtherId1() || group.getId() == temp.getOtherId2()) {
                    group.setGuest1(temp.getId());
                }
            }
            for (OptGroup temp : groups) {
                if ((group.getId() == temp.getOtherId1() || group.getId() == temp.getOtherId2()) && group.getGuest1() != temp.getId()) {
                    group.setGuest2(temp.getId());
                }
            }
        }

        List<String> errors = GroupsAndAssignmentValidator.validate(groups, map);
        for (OptGroup group : groups) {
            OptGroup.OBJECTS.save(group);
        }
        if (!errors.isEmpty()) {
            cont.setVisible(true);
            for (String msg : errors) {
                cont.error(msg);
            }
        }
    }
}