001package org.cpsolver.instructor.model;
002
003/**
004 * Attributes of an instructor. Each instructor can have a number of attributes and there are attribute preferences on teaching requests.
005 * Each attribute has an id, a name and a {@link Type}.
006 * 
007 * @version IFS 1.3 (Instructor Sectioning)<br>
008 *          Copyright (C) 2016 Tomas Muller<br>
009 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
010 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
011 * <br>
012 *          This library is free software; you can redistribute it and/or modify
013 *          it under the terms of the GNU Lesser General Public License as
014 *          published by the Free Software Foundation; either version 3 of the
015 *          License, or (at your option) any later version. <br>
016 * <br>
017 *          This library is distributed in the hope that it will be useful, but
018 *          WITHOUT ANY WARRANTY; without even the implied warranty of
019 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
020 *          Lesser General Public License for more details. <br>
021 * <br>
022 *          You should have received a copy of the GNU Lesser General Public
023 *          License along with this library; if not see
024 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
025 */
026public class Attribute {
027    private Long iAttributeId;
028    private String iAttributeName;
029    private Type iType;
030    
031    /**
032     * Constructor
033     * @param attributeId attribute id
034     * @param attributeName attribute name
035     * @param type attribute type
036     */
037    public Attribute(long attributeId, String attributeName, Type type) {
038        iAttributeId = attributeId;
039        iAttributeName = attributeName;
040        iType = type;
041    }
042    
043    /**
044     * Attribute id that was provided in the constructor
045     * @return attribute id
046     */
047    public Long getAttributeId() { return iAttributeId; }
048    
049    /**
050     * Attribute name that was provided in the constructor
051     * @return attribute name
052     */
053    public String getAttributeName() { return iAttributeName == null ? "A" + iAttributeId : iAttributeName; }
054    
055    /**
056     * Attribute type that was provided in the constructor
057     * @return attribute type
058     */
059    public Type getType() { return iType; }
060    
061    @Override
062    public int hashCode() {
063        return (getAttributeId() == null ? getAttributeName().hashCode() : getAttributeId().hashCode());
064    }
065    
066    @Override
067    public boolean equals(Object o) {
068        if (o == null || !(o instanceof Attribute)) return false;
069        Attribute a = (Attribute)o;
070        return getAttributeId() == null ? getAttributeName().equals(a.getAttributeName()) : getAttributeId().equals(a.getAttributeId());
071    }
072    
073    @Override
074    public String toString() { return getAttributeName() + " (" + getType() + ")"; }
075    
076    /**
077     * Attribute type. Each type has an id and a name. It can also define whether attributes of this type are required and/or conjunctive.
078     * If an attribute is required, this means that only instructors that have the attribute can be used, even if it is only preferred. This
079     * allows to put different preferences on multiple attribute that are required.
080     * If a teaching requests require two attributes that are of the same type which is conjunctive, only instructors that have BOTH attributes can be used.
081     * It the type is disjunctive (not conjunctive), it is sufficient for the instructor to have one of the two required attributes. 
082     */
083    public static class Type {
084        private Long iTypeId;
085        private String iTypeName;
086        private boolean iRequired;
087        private boolean iConjunctive;
088
089        /**
090         * Constructor
091         * @param typeId attribute type id
092         * @param typeName attribute type name
093         * @param conjunctive is attribute type conjunctive (if two attributes are required a student must have both). 
094         * @param required
095         */
096        public Type(long typeId, String typeName, boolean conjunctive, boolean required) {
097            iTypeId = typeId;
098            iTypeName = typeName;
099            iConjunctive = conjunctive;
100            iRequired = required;
101        }
102        
103        /**
104         * Attribute type id that was provided in the constructor
105         * @return attribute type id
106         */
107        public Long getTypeId() { return iTypeId; }
108        
109        /**
110         * Attribute type name that was provided in the constructor
111         * @return attribute type name
112         */
113        public String getTypeName() { return iTypeName == null ? "T" + iTypeId : iTypeName; }
114        
115        /**
116         * If an attribute is required, this means that only instructors that have the attribute can be used, even if it is only preferred. This
117         * allows to put different preferences on multiple attribute that are required.
118         * @return true if this attribute type is required
119         */
120        public boolean isRequired() { return iRequired; }
121        
122        /**
123         * If a teaching requests require two attributes that are of the same type which is conjunctive, only instructors that have BOTH attributes can be used.
124         * It the type is disjunctive (not conjunctive), it is sufficient for the instructor to have one of the two required attributes.
125         * @return true if this attribute type is conjunctive, false if disjunctive
126         */
127        public boolean isConjunctive() { return iConjunctive; }
128
129        @Override
130        public int hashCode() {
131            return getTypeId() == null ? getTypeName().hashCode() : getTypeId().hashCode();
132        }
133        
134        @Override
135        public boolean equals(Object o) {
136            if (o == null || !(o instanceof Type)) return false;
137            Type t = (Type)o;
138            return getTypeId() == null ? getTypeName().equals(t.getTypeName()) : getTypeId().equals(t.getTypeId());
139        }
140        
141        @Override
142        public String toString() { return getTypeName(); }
143    }
144
145}