package ttsolver.constraint;

import ifs.model.*;
import java.util.Set;
import ttsolver.model.*;

/**
 * Room constraint.
 * <br>
 * Classes with the same room can not overlap in time.
 * 
 * @author <a href="mailto:muller@ktiml.mff.cuni.cz">Tomas Muller</a>
 * @version 1.0
 */

public class RoomConstraint extends Constraint {
    private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(RoomConstraint.class);
    private Lecture[] iResource;
    private String iResourceId;
    private String iName;
    private int iSlotsPerDay;
    private int iDays;
    private long iPreference = 0;
    private String iDescription = null;
    
    /** Constructor
     * @param id room id
     * @param name room name
     * @param slotsPerDay number of slots per day
     * @param days number of days
     * @param description room description
     */
    public RoomConstraint(String id, String name, int slotsPerDay, int days, String description) {
        iSlotsPerDay = slotsPerDay;
        iDays = days;
        iResourceId = id;
        iName = name;
        iResource = new Lecture[iSlotsPerDay * iDays];
        iDescription = description;
        for (int i=0;i<iResource.length;i++)
            iResource[i]=null;
    }
    
    /** Room id */
    public String getResourceId() { return iResourceId; }
    /** Room name */
    public String getName() { return iName; }
    /** Number of slots per day */
    public int getSlotsPerDay() { return iSlotsPerDay; }
    /** Number of days */
    public int getDays() { return iDays; }

    public void computeConflicts(Value value, Set conflicts) {
        Placement placement = (Placement) value;
        if (!placement.getRoomId().equals(getResourceId())) return;
        Lecture lecture = (Lecture) value.variable();
        for (int i=0; i<placement.getTimeLocation().getSlots().length; i++) {
            int slot = placement.getTimeLocation().getSlots()[i];
            Lecture conf = iResource[slot];
            if (conf!=null && !lecture.equals(conf)) conflicts.add(conf.getAssignment());
        }
    }
    
    public boolean inConflict(Value value) {
        Placement placement = (Placement) value;
        if (!placement.getRoomId().equals(getResourceId())) return false;
        for (int i=0; i<placement.getTimeLocation().getSlots().length; i++) {
            int slot = placement.getTimeLocation().getSlots()[i];
            if (iResource[slot]!=null) return true;
        }
        return false;
    }
    

    public boolean isConsistent(Value value1, Value value2) {
        Placement p1 = (Placement) value1;
        Placement p2 = (Placement) value2;
        return !(
            p1.getRoomId().equals(getResourceId()) &&
            p1.getRoomId().equals(p2.getRoomId()) &&
            p1.getTimeLocation().hasIntersection(p2.getTimeLocation())
            );
    }
    
    public void assigned(long iteration, Value value) {
        super.assigned(iteration, value);
        Placement placement = (Placement) value;
        if (placement.getRoomId()==null || !placement.getRoomId().equals(getResourceId())) return;
        iPreference += placement.getRoomLocation().getPreference();
        Lecture lecture = (Lecture) value.variable();
        for (int i=0; i<placement.getTimeLocation().getSlots().length; i++) {
            int slot = placement.getTimeLocation().getSlots()[i];
            iResource[slot] = lecture;
        }
    }
    
    public void unassigned(long iteration, Value value) {
        super.unassigned(iteration, value);
        Placement placement = (Placement) value;
        if (placement.getRoomId()==null || !placement.getRoomId().equals(getResourceId())) return;
        iPreference -= placement.getRoomLocation().getPreference();
        Lecture lecture = (Lecture) value.variable();
        for (int i=0; i<placement.getTimeLocation().getSlots().length; i++) {
            int slot = placement.getTimeLocation().getSlots()[i];
            iResource[slot] = null;
        }
    }
        
    /** Lookup table getResource()[slot] -> lecture using this room placed in the given time slot (null if empty) */
    public Lecture[] getResource() { return iResource; }

    /** Number of useless slots for this room */
    public int countUselessSlots() {
        int ret = 0;
        for (int d=0;d<iDays;d++) {
            for (int s=1;s<iSlotsPerDay-1;s++) {
                int slot = d*iSlotsPerDay+s;
                if (iResource[slot-1]!=null && iResource[slot]==null && iResource[slot+1]!=null)
                    ret++;
            }
        }
        return ret;
    }
    
    /** Room usage */
    protected void printUsage(StringBuffer sb) {
        for (int slot=0;slot<getResource().length;slot++) {
            if (getResource()[slot]!=null) {
                int day = slot / edu.purdue.smas.timetable.util.Constants.SLOTS_PER_DAY;
                int time = (7*60)+30 + (30 * (slot % edu.purdue.smas.timetable.util.Constants.SLOTS_PER_DAY));
                int h = time / 60;
                int m = time % 60;
                String d = edu.purdue.smas.timetable.util.Constants.DAY_NAMES_SHORT[day];
                int slots = ((Placement)((Lecture)getResource()[slot]).getAssignment()).getTimeLocation().getLength();
                time += (30*slots);
                int h2 = time / 60;
                int m2 = time % 60;
                sb.append(sb.length()==0?"":",\n        ").append("["+d+(h>12?h-12:h)+":"+(m<10?"0":"")+m+(h>=12?"pm":"am")+"-"+(h2>12?h2-12:h2)+":"+(m2<10?"0":"")+m2+(h2>=12?"pm":"am")+"]=").append(((Lecture)iResource[slot]).getName());
                slot+=slots-1;
                //sb.append(sb.length()==0?"":", ").append("s"+(slot+1)+"=").append(((Lecture)getResource()[slot]).getName());
            }
        }
    }

    public String toString() {
        StringBuffer sb = new StringBuffer("Room{name="+getName()+" preference="+iPreference);
        printUsage(sb);
        sb.append("\n      }");
        return sb.toString();
    }
    /** Room description */
    public String getDescription() { return iDescription; }
}
