001package org.cpsolver.coursett.model;
002
003import java.util.HashMap;
004import java.util.Map;
005import java.util.TreeSet;
006
007import org.cpsolver.coursett.Constants;
008
009
010/**
011 * Room availability model.
012 * 
013 * @author  Tomáš Müller
014 * @version CourseTT 1.3 (University Course Timetabling)<br>
015 *          Copyright (C) 2006 - 2014 Tomáš Müller<br>
016 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
017 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
018 * <br>
019 *          This library is free software; you can redistribute it and/or modify
020 *          it under the terms of the GNU Lesser General Public License as
021 *          published by the Free Software Foundation; either version 3 of the
022 *          License, or (at your option) any later version. <br>
023 * <br>
024 *          This library is distributed in the hope that it will be useful, but
025 *          WITHOUT ANY WARRANTY; without even the implied warranty of
026 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
027 *          Lesser General Public License for more details. <br>
028 * <br>
029 *          You should have received a copy of the GNU Lesser General Public
030 *          License along with this library; if not see
031 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
032 */
033public class RoomSharingModel {
034        protected int iStep = 1;
035    protected Long[][] iPreference = null;
036    protected Long[] iDepartmentIds = null;
037    protected HashMap<Long, Integer> iDepartmentIdx = null;
038
039    public static Long sFreeForAllPref = Long.valueOf(-1);
040    public static Long sNotAvailablePref = Long.valueOf(-2);
041    public static char sFreeForAllPrefChar = '*';
042    public static char sNotAvailablePrefChar = '#';
043
044    public static Long sDefaultPref = sFreeForAllPref;
045    public static char sDefaultPrefChar = sFreeForAllPrefChar;
046
047    public char iFreeForAllPrefChar = sFreeForAllPrefChar;
048    public char iNotAvailablePrefChar = sNotAvailablePrefChar;
049    
050    private Map<Character, Long> iPatternMapping = null;
051
052    protected RoomSharingModel(int step) {
053        iStep = step;
054    }
055    
056    protected RoomSharingModel() {
057        this(6);
058    }
059    
060    public RoomSharingModel(int step, Map<Character, Long> managerIds, String pattern, Character freeForAllPrefChar, Character notAvailablePrefChar) {
061        iStep = step;
062        iPreference = new Long[getNrDays()][getNrTimes()];
063        iDepartmentIds = new Long[managerIds == null ? 0 : managerIds.size()];
064        iDepartmentIdx = new HashMap<Long, Integer>();
065        if (managerIds != null) {
066            iPatternMapping = new HashMap<Character, Long>(managerIds);
067            int i = 0;
068            for (Character ch: new TreeSet<Character>(managerIds.keySet())) {
069                Long id = managerIds.get(ch);
070                iDepartmentIds[i] = id;
071                iDepartmentIdx.put(id, i);
072                i++;
073            }
074        }
075        if (freeForAllPrefChar != null)
076            iFreeForAllPrefChar = freeForAllPrefChar;
077        if (notAvailablePrefChar != null)
078            iNotAvailablePrefChar = notAvailablePrefChar;
079
080        setPreferences(pattern);
081    }
082
083    public RoomSharingModel(int step, Long[] managerIds, String pattern, Character freeForAllPrefChar, Character notAvailablePrefChar) {
084        iStep = step;
085        iPreference = new Long[getNrDays()][getNrTimes()];
086        iDepartmentIds = new Long[managerIds.length];
087        iDepartmentIdx = new HashMap<Long, Integer>();
088        for (int i = 0; i < managerIds.length; i++) {
089            iDepartmentIds[i] = managerIds[i];
090            iDepartmentIdx.put(managerIds[i], i);
091        }
092        if (freeForAllPrefChar != null)
093            iFreeForAllPrefChar = freeForAllPrefChar;
094        if (notAvailablePrefChar != null)
095            iNotAvailablePrefChar = notAvailablePrefChar;
096
097        setPreferences(pattern);
098    }
099    
100    public char getFreeForAllPrefChar() { return iFreeForAllPrefChar; }
101    public void setFreeForAllPrefChar(char c) { iFreeForAllPrefChar = c; }
102
103    public char getNotAvailablePrefChar() { return iNotAvailablePrefChar; }
104    public void setNotAvailablePrefChar(char c) { iNotAvailablePrefChar = c; }
105
106    public boolean isFreeForAll(int day, int time) {
107        return sFreeForAllPref.equals(iPreference[day][time]);
108    }
109
110    public boolean isFreeForAll(int slot) {
111        int day = slot / Constants.SLOTS_PER_DAY;
112        int time = (slot % Constants.SLOTS_PER_DAY) / getStep();
113        return sFreeForAllPref.equals(iPreference[day][time]);
114    }
115
116    public boolean isNotAvailable(int day, int time) {
117        return sNotAvailablePref.equals(iPreference[day][time]);
118    }
119
120    public boolean isNotAvailable(int slot) {
121        int day = slot / Constants.SLOTS_PER_DAY;
122        int time = (slot % Constants.SLOTS_PER_DAY) / getStep();
123        return sNotAvailablePref.equals(iPreference[day][time]);
124    }
125
126    public boolean isAvailable(TimeLocation timeLocation, Long departmentId) {
127        for (int d = 0; d < Constants.NR_DAYS; d++) {
128            if ((Constants.DAY_CODES[d] & timeLocation.getDayCode()) == 0)
129                continue;
130            int startTime = timeLocation.getStartSlot() / getStep();
131            int endTime = (timeLocation.getStartSlot() + timeLocation.getLength() - 1) / getStep();
132            for (int t = startTime; t <= endTime; t++) {
133                Long pref = iPreference[d][t];
134                if (pref.equals(sNotAvailablePref))
135                    return false;
136                if (pref.equals(sFreeForAllPref))
137                    continue;
138                if (departmentId != null && !departmentId.equals(pref))
139                    return false;
140            }
141        }
142        return true;
143    }
144
145    public Long getDepartmentId(int day, int time) {
146        Long pref = iPreference[day][time];
147        if (pref.equals(sFreeForAllPref) || pref.equals(sNotAvailablePref))
148            return null;
149        return pref;
150    }
151
152    public Long getDepartmentId(int slot) {
153        int day = slot / Constants.SLOTS_PER_DAY;
154        int time = (slot % Constants.SLOTS_PER_DAY) / getStep();
155        return getDepartmentId(day, time);
156    }
157
158    public Long[] getDepartmentIds() {
159        return iDepartmentIds;
160    }
161
162    public int getNrDepartments() {
163        return (iDepartmentIds == null ? 0 : iDepartmentIds.length);
164    }
165
166    public int getIndex(Long departmentId) {
167        Integer idx = iDepartmentIdx.get(departmentId);
168        if (idx == null)
169            return -1;
170        return idx.intValue();
171    }
172    
173    public char getCharacter(Long departmentId) {
174        if (iPatternMapping != null) {
175            for (Map.Entry<Character, Long> e: iPatternMapping.entrySet()) {
176                if (e.getValue().equals(departmentId)) return e.getKey();
177            }
178        }
179        return (char) ('0' + getIndex(departmentId));
180    }
181    
182    public Long getDepartmentId(char ch) {
183        if (iPatternMapping != null)
184            return iPatternMapping.get(ch);
185        else
186            return iDepartmentIds[(ch - '0')];
187    }
188
189    public String getPreferences() {
190        StringBuffer sb = new StringBuffer();
191        for (int d = 0; d < getNrDays(); d++)
192            for (int t = 0; t < getNrTimes(); t++) {
193                if (iPreference[d][t].equals(sFreeForAllPref))
194                    sb.append(getFreeForAllPrefChar());
195                else if (iPreference[d][t].equals(sNotAvailablePref))
196                    sb.append(getNotAvailablePrefChar());
197                else
198                    sb.append(getCharacter(iPreference[d][t]));
199            }
200        return sb.toString();
201    }
202
203    public void setPreferences(String pattern) {
204        try {
205            int idx = 0;
206            for (int d = 0; d < getNrDays(); d++)
207                for (int t = 0; t < getNrTimes(); t++) {
208                    char pref = (pattern != null && idx < pattern.length() ? pattern.charAt(idx) : getFreeForAllPrefChar());
209                    idx++;
210                    if (pref == getNotAvailablePrefChar()) {
211                        iPreference[d][t] = sNotAvailablePref;
212                    } else if (pref == getFreeForAllPrefChar()) {
213                        iPreference[d][t] = sFreeForAllPref;
214                    } else {
215                        iPreference[d][t] = getDepartmentId(pref);
216                    }
217                }
218        } catch (NullPointerException e) {
219        } catch (IndexOutOfBoundsException e) {
220        }
221    }
222
223    public int getNrDays() {
224        return Constants.NR_DAYS;
225    }
226
227    public int getNrTimes() {
228        return Constants.SLOTS_PER_DAY / getStep();
229    }
230    
231    public int getStep() {
232        return iStep;
233    }
234}