/*
 * Copyright 2012 s_wolff.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.aegee.runanddine.information;

import java.util.*;

import org.aegee.runanddine.mail.MailRenderContext;
import org.aegee.runanddine.pathfinder.Course;
import org.aegee.runanddine.pathfinder.OptGroup;
import org.aegee.runanddine.runanddine.RunAndDine;
import org.aegee.runanddine.util.DateFormat;
import org.aegee.runanddine.util.data.ModelNotExistingException;
import org.apache.wicket.request.http.flow.AbortWithHttpErrorCodeException;

/**
 * MailRenderer for the InformationMail
 *
 * @author s_wolff
 */
public class InformationMailRenderer extends MailRenderContext {

    private static final String NO_VALUE_DEFAULT_VALUE = "__ERROR__";
    /**
     * Keys for RenderContext
     */
    private static final List<String> keys = Arrays.asList(
            "date", "motto", "course",
            "team", "team_contact", "team_kitchen", "team_food",
            "stationA", "stationA_course", "stationA_address", "stationA_contact", "stationA_addition",
            "stationB", "stationB_course", "stationB_address", "stationB_contact", "stationB_addition",
            "visitorA", "visitorA_contact", "visitorA_food",
            "visitorB", "visitorB_contact", "visitorB_food");

    /**
     * Create MailRenderer based on properties of given OptGroups
     *
     * @param group OptGroup containing the data to be rendered
     * @return InformationMailRenderer containing all information for rendering
     */
    public static InformationMailRenderer create(OptGroup group) {
        try {
            String course = group.getCourseAsName();

            // general information
            RunAndDine runAndDine = RunAndDine.OBJECTS.getById(group.getRunAndDineId());
            String date = DateFormat.format(runAndDine.getDate());
            String motto = runAndDine.getMotto();

            // infos about the team
            String team = getNames(group);
            String team_contact = getContact(group);
            String team_kitchen = group.getKitchen();
            String team_food = getFoodInfo(group);

            // infos about first visited group
            OptGroup other1 = OptGroup.OBJECTS.getById(group.getOtherId1());
            String station1 = getNames(other1);
            String station1_address = other1.getKitchen();
            String station1_contact = getContact(other1);
            String station1_comment = getAddressAddition(other1);
            String station1_course = Course.asName(group.getOtherCourse1());

            // infos about second visited group
            OptGroup other2 = OptGroup.OBJECTS.getById(group.getOtherId2());
            String station2 = getNames(other2);
            String station2_address = other2.getKitchen();
            String station2_contact = getContact(other2);
            String station2_comment = getAddressAddition(other2);
            String station2_course = Course.asName(group.getOtherCourse2());

            // infos about the visitors
            OptGroup guest1 = OptGroup.OBJECTS.getById(group.getGuest1());
            String visitor1 = getNames(guest1);
            String visitor1_contact = getContact(guest1);
            String visitor1_food = getFoodInfo(guest1);

            OptGroup guest2 = OptGroup.OBJECTS.getById(group.getGuest2());
            String visitor2 = getNames(guest2);
            String visitor2_contact = getContact(guest2);
            String visitor2_food = getFoodInfo(guest2);

            // this lets the station1 and station2 appear in the proper order for the renderer
            // e.g. if station1.course==Dessert and station2.course==Starter both indices are interchanged
            if (other1.getCourse() < other2.getCourse()) {
                return new InformationMailRenderer(date, motto, course,
                        team, team_contact, team_kitchen, team_food,
                        station1, station1_course, station1_address, station1_contact, station1_comment,
                        station2, station2_course, station2_address, station2_contact, station2_comment,
                        visitor1, visitor1_contact, visitor1_food, visitor2, visitor2_contact, visitor2_food);
            } else {
                return new InformationMailRenderer(date, motto, course,
                        team, team_contact, team_kitchen, team_food,
                        station2, station2_course, station2_address, station2_contact, station2_comment,
                        station1, station1_course, station1_address, station1_contact, station1_comment,
                        visitor1, visitor1_contact, visitor1_food, visitor2, visitor2_contact, visitor2_food);
            }
        } catch (ModelNotExistingException e) {
            throw new AbortWithHttpErrorCodeException(500, "Unrenderable exception");
        }
    }

    /**
     * Render names of group members
     *
     * @param g OptGroup containing member data
     * @return Formatted string with both names of group members
     */
    private static String getNames(OptGroup g) {
        return String.format("%s %s, %s %s", g.getFirstName1(), g.getLastName1(), g.getFirstName2(), g.getLastName2());
    }

    /**
     * Render address addition
     *
     * @param g OptGroup containing address addition
     * @return String containing either die address addition or a note that none
     * has to be considered
     */
    private static String getAddressAddition(OptGroup g) {
        return g.getAddressAddition() == null ? "[Nichts zu beachten]" : g.getAddressAddition();
    }

    /**
     * Render contact information
     *
     * @param g OptGroup containing contact data
     * @return String containing contact data of one or both group members or a
     * note that none is given
     */
    private static String getContact(OptGroup g) {
        String contact = g.getEmail1() + ", " + g.getEmail2();
        if (g.getPhone1() != null && !g.getPhone1().equals("")) {
            contact += ", " + g.getPhone1();
        }
        if (g.getPhone2() != null && !g.getPhone2().equals("")) {
            contact += ", " + g.getPhone2();
        }

        return contact == null ? "[keine Angabe]" : contact;
    }

    /**
     * Render food info
     *
     * @param g OptGroup containing data about allergies and veggie status
     * @return String indicating whether group members have allergies or are
     * veggies
     */
    private static String getFoodInfo(OptGroup g) {
        String foodInfo = "Allergien: " + g.getAllergies1().trim() + "; " + g.getAllergies2();
        String veggi = "keine Vegetarier";
        if (g.isVegetarian1() && g.isVegetarian2()) {
            veggi = "2 Vegetarier";
        } else if (g.isVegetarian1() || g.isVegetarian2()) {
            veggi = "1 Vegetarier";
        }
        return veggi + "\n" + foodInfo;
    }

    /**
     * Create MailRenderers for all given OptGroups
     *
     * @param groups OptGroups to be processed
     * @return Map of InformationMailRenderers for all given OptGroups using the
     * OptGroup as key
     */
    public static Map<OptGroup, InformationMailRenderer> createAll(OptGroup... groups) {
        Map<OptGroup, InformationMailRenderer> map = new HashMap<OptGroup, InformationMailRenderer>(groups.length);
        for (OptGroup group : groups) {
            map.put(group, InformationMailRenderer.create(group));
        }
        return map;
    }

    public static List<String> getRenderableKeys() {
        return new ArrayList<String>(keys);
    }

    private InformationMailRenderer(Object... values) {
        this(createDictFromValues(values));
    }

    private InformationMailRenderer(Map<String, String> context) {
        super(context);
    }

    private static Map<String, String> createDictFromValues(Object[] values) {
        assert values.length == keys.size();
        Map<String, String> dict = new HashMap<String, String>(values.length);
        for (int i = 0; i < values.length; i++) {
            dict.put(keys.get(i), values[i] == null ? NO_VALUE_DEFAULT_VALUE : values[i].toString());
        }
        return dict;
    }
}
