package ru.hflabs.rcd.model.document;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import ru.hflabs.rcd.model.Descriptioned;
import ru.hflabs.rcd.model.ManyToOne;
import ru.hflabs.rcd.model.Named;
import ru.hflabs.rcd.model.OneToMany;
import ru.hflabs.rcd.model.annotation.Hashed;
import ru.hflabs.rcd.model.annotation.Indexed;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlTransient;
import java.util.Collection;
import static ru.hflabs.util.core.EqualsUtil.lowerCaseEquals;
import static ru.hflabs.util.core.EqualsUtil.lowerCaseHashCode;
/**
* Класс <class>MetaField</class> описывает МЕТА-информацию поля справочника
*
* @see Dictionary
*/
@Getter
@Setter
@Indexed(
id = MetaField.PRIMARY_KEY,
fields = {
@Indexed.Field(MetaField.HISTORY_ID),
@Indexed.Field(MetaField.CHANGE_TYPE),
@Indexed.Field(MetaField.CHANGE_DATE),
@Indexed.Field(MetaField.DICTIONARY_ID),
@Indexed.Field(value = MetaField.NAME, search = true),
@Indexed.Field(value = MetaField.DESCRIPTION, search = true),
@Indexed.Field(MetaField.TYPE),
@Indexed.Field(MetaField.FLAGS)
}
)
@Hashed(ignore = {MetaField.PRIMARY_KEY, MetaField.HISTORY_ID})
public final class MetaField extends DocumentTemplate implements Named, Descriptioned, ManyToOne<Dictionary>, OneToMany<Field> {
private static final long serialVersionUID = 6312797153253711953L;
/** Название МЕТА-поля по умолчанию */
public static final String DEFAULT_NAME = "CODE";
/** Позиция МЕТА-поля по умолчанию */
public static final int DEFAULT_ORDINAL = 0;
/*
* Название полей с идентификаторами
*/
public static final String DICTIONARY_ID = "dictionaryId";
public static final String ORDINAL = "ordinal";
public static final String TYPE = "type";
public static final String FLAGS = "flags";
/*
* Доступные типы флагов
*/
public static final int FLAG_UNIQUE = 0b001;
public static final String FLAG_UNIQUE_NAME = "unique";
public static final int FLAG_PRIMARY = 0b011;
public static final String FLAG_PRIMARY_NAME = "primary";
public static final int FLAG_HIDDEN = 0b100;
public static final String FLAG_HIDDEN_NAME = "hidden";
/** Идентификатор справочника, к которому относится это поле */
@NotNull
@Size(max = PRIMARY_KEY_MAX_SIZE)
private String dictionaryId;
/** Справочник, к которому относится поле */
private transient Dictionary relative;
/** Уникальное название поля внутри справочника */
@NotNull
@Size(min = NAME_MIN_SIZE, max = NAME_MAX_SIZE)
private String name;
/** Описание поля */
@Size(max = DESCRIPTION_SIZE)
private String description;
/** Позиция поля относительно других */
private Integer ordinal;
/** Тип поля */
private MetaFieldType type = MetaFieldType.STRING;
/** Флаги поля */
private int flags = 0;
/** Коллекция значений полей */
private Collection<Field> descendants;
@XmlTransient
@Override
public String getRelativeId() {
return getDictionaryId();
}
@XmlTransient
@Override
public Dictionary getRelative() {
return relative;
}
@Override
public void setRelative(Dictionary relative) {
this.relative = relative;
setDictionaryId(this.relative != null ? this.relative.getId() : null);
}
@XmlTransient
public Integer getOrdinal() {
return ordinal;
}
@XmlTransient
public int getFlags() {
return flags;
}
public boolean isFlagEstablished(int targetFlag) {
return (flags & targetFlag) == targetFlag;
}
public void establishFlags(int... targetFlags) {
int currentFlags = getFlags();
for (int f : targetFlags) {
currentFlags = currentFlags | f;
}
setFlags(currentFlags);
}
public void resetFlags(int... targetFlags) {
int currentFlags = getFlags();
for (int f : targetFlags) {
currentFlags = currentFlags & ~f;
}
setFlags(currentFlags);
}
public void changeFlag(boolean value, int flag) {
if (value) {
establishFlags(flag);
} else {
resetFlags(flag);
}
}
@XmlTransient
@Override
public Collection<Field> getDescendants() {
return descendants;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (dictionaryId != null ? dictionaryId.hashCode() : 0);
result = 31 * result + lowerCaseHashCode(name);
result = 31 * result + (description != null ? description.hashCode() : 0);
result = 31 * result + (type != null ? type.hashCode() : 0);
result = 31 * result + flags;
return result;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
MetaField that = (MetaField) o;
if (dictionaryId != null ? !dictionaryId.equals(that.dictionaryId) : that.dictionaryId != null) {
return false;
}
if (!lowerCaseEquals(name, that.name)) {
return false;
}
if (description != null ? !description.equalsIgnoreCase(that.description) : that.description != null) {
return false;
}
if (type != that.type) {
return false;
}
if (flags != that.flags) {
return false;
}
return true;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.appendSuper(super.toString())
.append(DICTIONARY_ID, getDictionaryId())
.append(NAME, getName())
.append(ORDINAL, getOrdinal())
.append(FLAGS, getFlags())
.toString();
}
}