/*
* Copyright (C) 2014 GG-Net GmbH - Oliver Günther
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.ggnet.dwoss.spec.entity;
import java.io.Serializable;
import java.util.EnumSet;
import java.util.Set;
import javax.persistence.*;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Null;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlTransient;
import eu.ggnet.dwoss.rules.ProductGroup;
import eu.ggnet.dwoss.util.INoteModel;
import eu.ggnet.dwoss.util.persistence.EagerAble;
import lombok.*;
import static javax.persistence.CascadeType.*;
/**
* The minimal abstract information about a ProductSpec.
* <p>
* A ProductSpec has a weak reference to uniqueunit.Product.
* <p>
* @composed 1 - n ProductModel
* @author oliver.guenther
*/
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@NamedQueries({
@NamedQuery(name = "ProductSpec.byPartNo", query = "select s from ProductSpec s where s.partNo = ?1"),
@NamedQuery(name = "ProductSpec.byProductId", query = "select s from ProductSpec s where s.productId = ?1"),
@NamedQuery(name = "ProductSpec.byProductIds", query = "SELECT s FROM ProductSpec s WHERE s.productId IN (?1)")
})
@EqualsAndHashCode(of = "id")
@ToString
public abstract class ProductSpec implements Serializable, EagerAble {
@RequiredArgsConstructor
public static enum Extra implements INoteModel {
USB_3("USB 3"),
CARD_READER("Kartenleser"),
WLAN_TO_G("WLAN b + g"),
WLAN_TO_N("WLAN b + g + n"),
UMTS("UMTS (3G)", 30.),
KAMERA("Webcam"),
BLUETOOTH("Bluetooth"),
FINGER_SCANNER("Fingerabdruck Scanner"),
PS_2("PS2"),
E_SATA("eSATA"),
THREE_D("3D fähig"),
PIVOT("Pivot Funktion"),
HIGHT_CHANGEABLE("höhenverstellbar"),
SPEAKERS("Lautsprecher"),
TOUCH("Touchscreen"),
PENSLOT("Stifthalterung"),
CONVERTABLE("Convertable (Display drehbar)"),
BATTERY_INTEGRATED("Akku integriert"),
TV_TUNER("TV Tuner"),
INFRARED_RESCEIVER("Infrarot Empfänger"),
DUAL_DISPLAY_TABLET("Dual Display Tablet"),
MEDIA_STATION("Multimedia Wohnzimmer PC"),
LTE("LTE (4G)", 30.),
DUAL_LOAD("Dual Load"),
THUNDERBOLT("Thunderbolt"),
COVER("Cover"),
GORILLA_GLASS("Gorilla Glass"),
KEYBOARD_BACKGROUND_LIGHT("beleuchtete Tastatur"),
DUAL_SIM("Dual-SIM"),
LIGHTNING("Lightning"),
WLAN_AC("WLAN ac"),
IPS_DISPLAY("IPS-Display"),
USB_TYPE_C("USB Typ-C"),
THREE_SIXTY_DEGREE_TORQUE_HINGE("360° Dual-Torque-Hinge"),
VGA_ADAPTER("VGA-Adapter"),
MAGSAFE_POWER_ADAPTER("MagSafe Power Adapter"),
REPLACEMENT_STRAP("Ersatzarmband"),
BLUE_LIGHT_FILTER("Blaulichtfilter");
@Getter
private final String note;
@Getter
private final double economicValue;
private Extra(String note) {
this(note, 0);
}
}
public static ProductSpec newInstance(ProductGroup group) {
switch (group) {
case DESKTOP:
case SERVER:
return new Desktop();
case DESKTOP_BUNDLE:
return new DesktopBundle();
case ALL_IN_ONE:
return new AllInOne();
case TABLET_SMARTPHONE:
return new Tablet();
case MONITOR:
case TV:
return new Monitor();
case NOTEBOOK:
return new Notebook();
case MISC:
case PROJECTOR:
case PHONE:
return new BasicSpec();
case COMMENTARY:
default:
}
throw new RuntimeException(group + " not supported. Think about");
}
@XmlTransient
@Id
@GeneratedValue
@Getter
private long id;
@XmlTransient
@Version
private short optLock;
@Valid
@ManyToOne(cascade = {DETACH, MERGE, REFRESH}, optional = false)
@Getter
private ProductModel model;
/**
* PartNo of the Manufacturer.
*/
@Column(unique = true)
@Basic(optional = false)
@NotNull
@XmlAttribute
@Getter
@Setter
private String partNo;
/**
* Optional uniqueunit.Product.id.
* <p>
* This is the weak reference to unqiueunit.Product
*/
@Getter
@Setter
@XmlTransient
@Column(unique = true)
private Long productId;
@Getter
@Setter
@XmlAttribute
@Column(columnDefinition = "DECIMAL(7,2)")
private Double economicValue;
public ProductSpec() {
}
/**
* Non Productive Constructor
* <p>
* @param id the database id, normally auto generated.
*/
ProductSpec(long id) {
this.id = id;
}
public ProductSpec(String partNo, Long productId) {
this.partNo = partNo;
this.productId = productId;
}
public Set<Extra> getDefaultExtras() {
return EnumSet.allOf(Extra.class);
}
public void setModel(ProductModel model) {
if ( model == null && this.model == null ) return;
if ( this.model != null && this.model == model ) return;
if ( this.model != null ) this.model.specs.remove(this);
if ( model != null ) model.specs.add(this);
this.model = model;
}
@Override
public void fetchEager() {
if ( getModel() != null ) getModel().fetchEager();
}
/**
* Returns null if the instance is valid, or a string representing the error.
* <p>
* @return null if the instance is valid, or a string representing the error.
*/
@Null
public String getViolationMessage() {
if ( model == null
|| model.getFamily() == null
|| model.getFamily().getSeries() == null
|| model.getFamily().getSeries().getBrand() == null
|| model.getFamily().getSeries().getBrand().getManufacturer().getPartNoSupport() == null )
return null;
return model.getFamily().getSeries().getBrand().getManufacturer().getPartNoSupport().violationMessages(partNo);
}
// TODO: Please realize this through Validation Groups.
@PrePersist
@PreUpdate
private void prePersitValidate() {
if ( model == null ) throw new RuntimeException("Model is null");
}
}