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 Tomáš Müller<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    private Attribute iParentAttribute;
031    
032    /**
033     * Constructor
034     * @param attributeId attribute id
035     * @param attributeName attribute name
036     * @param type attribute type
037     */
038    public Attribute(long attributeId, String attributeName, Type type) {
039        iAttributeId = attributeId;
040        iAttributeName = attributeName;
041        iType = type;
042    }
043    
044    /**
045     * Attribute id that was provided in the constructor
046     * @return attribute id
047     */
048    public Long getAttributeId() { return iAttributeId; }
049    
050    /**
051     * Attribute name that was provided in the constructor
052     * @return attribute name
053     */
054    public String getAttributeName() { return iAttributeName == null ? "A" + iAttributeId : iAttributeName; }
055    
056    /**
057     * Attribute type that was provided in the constructor
058     * @return attribute type
059     */
060    public Type getType() { return iType; }
061    
062    /**
063     * Parent attribute
064     */
065    public Attribute getParentAttribute() { return iParentAttribute; }
066    
067    /**
068     * Parent attribute
069     */
070    public void setParentAttribute(Attribute parent) { iParentAttribute = parent; }
071    
072    @Override
073    public int hashCode() {
074        return (getAttributeId() == null ? getAttributeName().hashCode() : getAttributeId().hashCode());
075    }
076    
077    @Override
078    public boolean equals(Object o) {
079        if (o == null || !(o instanceof Attribute)) return false;
080        Attribute a = (Attribute)o;
081        return getAttributeId() == null ? getAttributeName().equals(a.getAttributeName()) : getAttributeId().equals(a.getAttributeId());
082    }
083    
084    @Override
085    public String toString() { return getAttributeName() + " (" + getType() + ")"; }
086    
087    /**
088     * Attribute type. Each type has an id and a name. It can also define whether attributes of this type are required and/or conjunctive.
089     * If an attribute is required, this means that only instructors that have the attribute can be used, even if it is only preferred. This
090     * allows to put different preferences on multiple attribute that are required.
091     * 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.
092     * It the type is disjunctive (not conjunctive), it is sufficient for the instructor to have one of the two required attributes. 
093     */
094    public static class Type {
095        private Long iTypeId;
096        private String iTypeName;
097        private boolean iRequired;
098        private boolean iConjunctive;
099
100        /**
101         * Constructor
102         * @param typeId attribute type id
103         * @param typeName attribute type name
104         * @param conjunctive is attribute type conjunctive (if two attributes are required a student must have both). 
105         * @param required
106         */
107        public Type(long typeId, String typeName, boolean conjunctive, boolean required) {
108            iTypeId = typeId;
109            iTypeName = typeName;
110            iConjunctive = conjunctive;
111            iRequired = required;
112        }
113        
114        /**
115         * Attribute type id that was provided in the constructor
116         * @return attribute type id
117         */
118        public Long getTypeId() { return iTypeId; }
119        
120        /**
121         * Attribute type name that was provided in the constructor
122         * @return attribute type name
123         */
124        public String getTypeName() { return iTypeName == null ? "T" + iTypeId : iTypeName; }
125        
126        /**
127         * If an attribute is required, this means that only instructors that have the attribute can be used, even if it is only preferred. This
128         * allows to put different preferences on multiple attribute that are required.
129         * @return true if this attribute type is required
130         */
131        public boolean isRequired() { return iRequired; }
132        
133        /**
134         * 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.
135         * It the type is disjunctive (not conjunctive), it is sufficient for the instructor to have one of the two required attributes.
136         * @return true if this attribute type is conjunctive, false if disjunctive
137         */
138        public boolean isConjunctive() { return iConjunctive; }
139
140        @Override
141        public int hashCode() {
142            return getTypeId() == null ? getTypeName().hashCode() : getTypeId().hashCode();
143        }
144        
145        @Override
146        public boolean equals(Object o) {
147            if (o == null || !(o instanceof Type)) return false;
148            Type t = (Type)o;
149            return getTypeId() == null ? getTypeName().equals(t.getTypeName()) : getTypeId().equals(t.getTypeId());
150        }
151        
152        @Override
153        public String toString() { return getTypeName(); }
154    }
155
156}