package org.aegee.runanddine.pathfinder;

import java.util.ArrayList;
import java.util.List;

import org.aegee.runanddine.registration.GroupRegistration;
import org.aegee.runanddine.registration.SingleRegistration;
import org.aegee.runanddine.util.model.Model;

/**
 * Model for persistent OptGroups that store information
 * about a group which is built during optimization
 */
public class OptGroup extends Model {

    private static final long serialVersionUID = 1L;
    
    /**
     * Manager for persistent OptGroups
     */
    public static final OptGroupManager OBJECTS = OptGroupManager.getInstance();
    
    /**
     * ID of related RunAndDine
     */
    private int runAndDineId;

    /**
     * Set ID of related RunAndDine
     * @param runAndDineId ID of RunAndDine the OptGroup is related to
     */
    public void setRunAndDineId(int runAndDineId) {
        this.runAndDineId = runAndDineId;
    }

    /**
     * Get ID of related RunAndDine
     * @return ID of RunAndDine the OptGroup is related to
     */
    public int getRunAndDineId() {
        return runAndDineId;
    }
    
    /**
     * Abstract ID for OptGroup
     */
    private int abstractId;
    
    /**
     * Course the OptGroup has to prepare
     */
    private int course;
    
    /**
     * Flag indicating if OptGroup was a GroupRegistration
     */
    private boolean readyMade;
    
    /**
     * SingleRegistration of first group member
     */
    private SingleRegistration participant1;
    
    /**
     * SingleRegistration of second group member
     */
    private SingleRegistration participant2;
    
    /**
     * GroupRegistration of both group members
     */
    private GroupRegistration groupreg;
    
    /**
     * ID of first group this OptGroup visits
     */
    private int otherId1;
    
    /**
     * Course number of first group this OptGroup visits
     */
    private int otherCourse1;
    
    /**
     * ID of second group this OptGroup visits
     */
    private int otherId2;
    
    /**
     * Course number of second group this OptGroup visits
     */
    private int otherCourse2;
    
    /**
     * ID of first group this group has as guests
     */
    private int guest1;
    
    /**
     * ID of second group this group has as guests
     */
    private int guest2;

    public OptGroup(GroupRegistration reg) {
        this.readyMade = true;
        this.groupreg = reg;
    }

    public OptGroup(SingleRegistration reg1, SingleRegistration reg2) {
        this.readyMade = false;
        this.participant1 = reg1;
        this.participant2 = reg2;
    }

    /**
     * Check whether OptGroup was a GroupRegistration
     * @return OptGroup is a GroupRegistration
     */
    public boolean isGroupRegistration() {
        return readyMade;
    }

    /**
     * If the group is not readyMade the address of the first participant is
     * chosen
     *
     * @return address of the kitchen
     */
    public String getKitchen() {
        if (readyMade) {
            return this.groupreg.getStreetName() + " " + this.groupreg.getStreetNo();
        } else {
            if (this.participant1.isKitchenAvailable()) {
                return this.participant1.getStreetName() + " " + this.participant1.getStreetNo();
            } else {
                return this.participant2.getStreetName() + " " + this.participant2.getStreetNo();
            }
        }
    }

    /**
     * Get number of course this group is having first meal at
     * @return the static final int of the course where this group is having a
     * meal
     * @see Course
     */
    public int getOtherCourse1() {
        return otherCourse1;
    }

    /**
     * Get number of source this group is having second meal at
     * @return the static final int of the course where this group is having a
     * meal
     * @see Course
     */
    public int getOtherCourse2() {
        return otherCourse2;
    }

    /**
     * Set number of course this group is having first meal at
     * @param otherCourse1 which course the group is having at id1's place
     */
    public void setOtherCourse1(int otherCourse1) {
        this.otherCourse1 = otherCourse1;
    }

    /**
     * Set number of source this group is having second meal at
     * @param otherCourse2 which course the group is having at id2's place
     */
    public void setOtherCourse2(int otherCourse2) {
        this.otherCourse2 = otherCourse2;
    }

    /**
     * Get ID of group where this group is having first meal at
     * @return id where the group is having a meal
     */
    public int getOtherId1() {
        return otherId1;
    }

    /**
     * Get ID of gorup where this group is having second meal at
     * @return id where the group is having a meal
     */
    public int getOtherId2() {
        return otherId2;
    }

    /**
     *
     * @param otherId1 id where the group is having a meal
     */
    public void setOtherId1(int otherId1) {
        this.otherId1 = otherId1;
    }

    /**
     * Set ID of group where this group is having first meal at
     * @param otherId2 id where the group is having a meal
     */
    public void setOtherId2(int otherId2) {
        this.otherId2 = otherId2;
    }

    /**
     * Set ID of gorup where this gorup is having second meal at
     * @return the abstract id this group is mapped to
     */
    public int getAbstractId() {
        return abstractId;
    }

    /**
     * Set abstract ID of this group
     * @param id the abstract id this group is mapped to
     */
    public void setAbstractId(int id) {
        this.abstractId = id;
    }

    /**
     * Get number of course this group is preparing
     * @return static final int of the course this group is preparing
     * @see Course
     */
    public int getCourse() {
        return course;
    }

    /**
     * Map number of course this group is preparing to its name
     * @return Name of course this group is preparing
     */
    public String getCourseAsName() {
        switch (this.getCourse()) {
            case Course.DESSERT:
                return "Nachspeise";
            case Course.MAIN:
                return "Haupspeise";
            case Course.HORS_DOEUVRE:
                return "Vorspeise";
            default:
                return null;
        }
    }

    /**
     * Set number of course this group is preparing
     * @param course int of the course this group is preparing
     * @see Course
     */
    public void setCourse(int course) {
        this.course = course;
    }

    /**
     * Get ID of first group this group has as guests
     * @return id of one of the guests eating at this group's place
     */
    public int getGuest1() {
        return guest1;
    }

    /**
     * Get ID of second group this group has as guests
     * @return id of one of the guests eating at this group's place
     */
    public int getGuest2() {
        return guest2;
    }

    /**
     * Set ID of first group this group has as guests
     * @param guest1 id of one of the guests
     */
    public void setGuest1(int guest1) {
        this.guest1 = guest1;
    }

    /**
     * Set ID of second group this group has as guests
     * @param guest2 id of one of the guests
     */
    public void setGuest2(int guest2) {
        this.guest2 = guest2;
    }

    /**
     * Get SingleRegistration of first group member
     * @return SingleRegistration of first group member
     */
    public SingleRegistration getFirstParticipant() {
        return this.participant1;
    }

    /**
     * Get SingleRegistration of second group member
     * @return SingleRegistration of second group member
     */
    public SingleRegistration getSecondParticipant() {
        return this.participant2;
    }

    /**
     * Get GroupRegistration of both group members
     * @return GroupRegistration of both group members
     */
    public GroupRegistration getGroupRegistration() {
        return this.groupreg;
    }

    /**
     * Get concatenated name of first group member
     * @return Concatenated name
     */
    public String getName1() {
        return getFirstName1() + " " + getLastName1();
    }

    /**
     * Get concatenated name of second group member
     * @return Concatenated name
     */
    public String getName2() {
        return getFirstName2() + " " + getLastName2();
    }

    /**
     * Get first name of first group member
     * @return First name
     */
    public String getFirstName1() {
        return (readyMade ? this.groupreg.getFirstName1() : this.participant1.getFirstName());
    }

    /**
     * Get first name of second group member
     * @return First name
     */
    public String getFirstName2() {
        return (readyMade ? this.groupreg.getFirstName2() : this.participant2.getFirstName());
    }

    /**
     * Get last name of first group member
     * @return Last name
     */
    public String getLastName1() {
        return (readyMade ? this.groupreg.getLastName1() : this.participant1.getLastName());
    }

    /**
     * Get last name of second group member
     * @return 
     */
    public String getLastName2() {
        return (readyMade ? this.groupreg.getLastName2() : this.participant2.getLastName());
    }

    /**
     * Get email of first group member
     * @return Email
     */
    public String getEmail1() {
        return (readyMade ? this.groupreg.getEmail1() : this.participant1.getEmail());
    }

    /**
     * Get email of second group member
     * @return Email
     */
    public String getEmail2() {
        return (readyMade ? this.groupreg.getEmail2() : this.participant2.getEmail());
    }

    /**
     * Check whether first group member is vegetarian
     * @return First group member is vegetarian
     */
    public boolean isVegetarian1() {
        return (readyMade ? this.groupreg.isVegetarian1() : this.participant1.isVegetarian());
    }

    /**
     * Check whether second group member is vegetarian
     * @return Second group member is vegetarian
     */
    public boolean isVegetarian2() {
        return (readyMade ? this.groupreg.isVegetarian2() : this.participant2.isVegetarian());
    }

    /**
     * Get allergies of first group member
     * @return Allergies
     */
    public String getAllergies1() {
        return (readyMade ? this.groupreg.getAllergies1() : this.participant1.getAllergies());
    }

    /**
     * Get allergies of second group member
     * @return Allergies
     */
    public String getAllergies2() {
        return (readyMade ? this.groupreg.getAllergies2() : this.participant2.getAllergies());
    }
    
    /**
     * Get the postal code of a group
     * @return PostalCode
     */
    public String getPostalCode() {
        return (readyMade ? this.groupreg.getPostalCode() : this.participant1.getPostalCode());
    }
    
    /**
     * Get the city of a group
     * @return City
     */
    public String getCity() {
        return (readyMade ? this.groupreg.getCity() : this.participant1.getCity());
    }
    
    /**
     * Get the address with postal code and city
     * @return address
     */
    public String getAddress() {
        return String.format("%s %s %s",getKitchen(), getPostalCode(), getCity());
    }
    
    /**
     * Dummy for wicket
     */
    public void setAddress(String addr) {
    }

    /**
     * Conversion to string for debugging
     * @return Debug information
     */
    @Override
    public String toString() {
        return "[" + getFirstName1() + " " + getLastName1() + ", "
                + getFirstName2() + " " + getLastName2() + ", preparing: "
                + course + ", eating: " + otherCourse1 + " at " + otherId1
                + " and " + otherCourse2 + " at " + otherId2 + "]";
    }

    /**
     * Get all OptGroups for RunAndDine thar are no GroupRegistrations
     * @param runAndDineId ID of related RunAndDine
     * @return List of matching OptGroups
     */
    public static List<OptGroup> getAllSingleGroups(int runAndDineId) {
        List<OptGroup> optGroups = OBJECTS.getAllByRunAndDineId(runAndDineId);
        List<OptGroup> singleGroups = new ArrayList<OptGroup>(optGroups.size());
        for (OptGroup g : optGroups) {
            if (!g.isGroupRegistration()) {
                singleGroups.add(g);
            }
        }
        return singleGroups;
    }

    /**
     * Get phone number of first group member
     * @return Phone number
     */
    public String getPhone1() {
        return readyMade ? this.groupreg.getPhone1() : this.participant1.getPhone();
    }

    /**
     * Get phone number of second group member
     * @return Phone number
     */
    public String getPhone2() {
        return readyMade ? this.groupreg.getPhone2() : this.participant2.getPhone();
    }

    /**
     * Get concatenated names of both group members
     * @return Names
     */
    public String getNames() {
        return getName1() + ", " + getName2();
    }

    /**
     * Get abstract group ID concatenated with names of both group members
     * @return Abstract group ID and names
     */
    public String getNamesAndAbstractId() {
        return abstractId + ": " + getNames();
    }

    /**
     * Get address addition of group
     * @return Address addition
     */
    public String getAddressAddition() {
        if (readyMade) {
            return this.groupreg.getAdressAddition();
        } else if (this.participant1.isKitchenAvailable()) {
            return this.participant1.getAddressAddition();
        } else {
            return this.participant2.getAddressAddition();
        }
    }
}