    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}