/*
 * 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.pathfinder.optimizers;

import java.util.*;

import org.aegee.runanddine.RunAndDineApplication;
import org.aegee.runanddine.pathfinder.OptGroup;

/**
 *
 * @author s_wolff
 */
public class OptGroupWrappers {

    private OptGroupWrappers() {
    }

    /**
     * Creates wrapper objects for the provided opt groups.
     *
     * @param groups
     * @return group wrappers
     */
    public static List<OptGroupWrapper> makeWrappers(Collection<OptGroup> groups) {
        ArrayList<OptGroupWrapper> wrappers = new ArrayList<OptGroupWrapper>(groups.size());
        int idCounter = 0;
        for (OptGroup g : groups) {
            wrappers.add(new OptGroupWrapper(g, idCounter));
            idCounter++;
        }
        return wrappers;
    }

    /**
     * sets the
     * <code>OptGroupWrapper.abstractGroupMapping</code> variable on every
     * <code>OptGroupWrapper</code> instance.
     *
     * @param abstractGroups abstract groups
     * @param mapping mapping abs->opt groups
     */
    public static void setOptGroupWrapperMappings(Collection<OptGroupWrapper> optGroupWrappers, Map<Integer, Integer> mapping) {
        Map<Integer, Integer> reverseMapping = new HashMap<Integer, Integer>(mapping.size());
        for (int key : mapping.keySet()) {
            reverseMapping.put(mapping.get(key), key);
        }

        for (OptGroupWrapper g : optGroupWrappers) {
            g.setAbstractGroupMapping(reverseMapping.get(g.getId()));
        }
    }

    /**
     * Up until now all
     * <code>OptGroupWrapper</code>s have a reference to the abstract group they
     * represent. Now we want to edit the
     * <code>OptGroup</code>s so that they now where to go, where to, what to
     * cook without the abstract groups and without the wrapper.
     *
     * @param optGroupWrappers opt group wrappers with mapping to abstract
     * groups
     * @param abstractGroup abstract grous
     */
    public static void setOptGroupAssignments(Collection<OptGroupWrapper> optGroupWrappers, Collection<AbstractGroup> abstractGroup) {
        TreeMap<Integer, AbstractGroup> absMap = new TreeMap<Integer, AbstractGroup>();
        TreeMap<Integer, OptGroupWrapper> wrapMap = new TreeMap<Integer, OptGroupWrapper>();

        for (AbstractGroup absGroup : abstractGroup) {
            absMap.put(absGroup.getId(), absGroup);
        }

        for (OptGroupWrapper wrapper : optGroupWrappers) {
            wrapMap.put(wrapper.getAbstractGroupMapping(), wrapper);
        }

        for (OptGroupWrapper wrap : optGroupWrappers) {
            int abstractId = wrap.getAbstractGroupMapping();
            AbstractGroup absGroup = absMap.get(abstractId);
            OptGroup group = wrap.getWrappedOptGroup();

            group.setAbstractId(abstractId);
            group.setCourse(absGroup.getCourse());
            group.setGuest1(wrapMap.get(absGroup.getGuest1()).getWrappedOptGroup().getId());
            group.setGuest2(wrapMap.get(absGroup.getGuest2()).getWrappedOptGroup().getId());
        }
        
        for (OptGroupWrapper wrap : optGroupWrappers) {
            int abstractId = wrap.getAbstractGroupMapping();
            AbstractGroup absGroup = absMap.get(abstractId);
            OptGroup group = wrap.getWrappedOptGroup();
            
            for (AbstractGroup temp : abstractGroup) {
                if (temp.hasGuest(abstractId)) {
                    group.setOtherId1(wrapMap.get(temp.getId()).getWrappedOptGroup().getId());
                    group.setOtherCourse1(wrapMap.get(temp.getId()).getWrappedOptGroup().getCourse());
                }
            }

            for (AbstractGroup temp : abstractGroup) {
                if (temp.hasGuest(abstractId) && wrapMap.get(temp.getId()).getWrappedOptGroup().getId() != group.getOtherId1()) {
                    group.setOtherId2(wrapMap.get(temp.getId()).getWrappedOptGroup().getId());
                    group.setOtherCourse2(wrapMap.get(temp.getId()).getWrappedOptGroup().getCourse());
                }
            }

            OptGroup.OBJECTS.save(group);
        }
    }
}
