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