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