package be.iminds.jfed.gts_highlevel.model;

import be.iminds.jfed.gts_highlevel.util.UnixEpochToZonedDateTimeAdapter;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Objects;

/**
 * User: twalcari
 * Date: 9/17/2015
 * Time: 16:47
 */
@XmlRootElement(name = "reservation")
public class GtsXmlReservation {
    private final IntegerProperty id = new SimpleIntegerProperty();
    private final ObjectProperty<ZonedDateTime> startTime = new SimpleObjectProperty<>();
    private final ObjectProperty<ZonedDateTime> endTime = new SimpleObjectProperty<>();    //from unix epoch in millis
    private final StringProperty projectName = new SimpleStringProperty();
    private final StringProperty resourcesProviderId = new SimpleStringProperty();
    private final ObjectProperty<Status> status = new SimpleObjectProperty<>();
    private final ObservableList<GtsXmlReservation> children = FXCollections.observableArrayList();

    public GtsXmlReservation() {
    }

    public GtsXmlReservation(GtsXmlReservation res) {
        this.id.set(res.id.get());
        this.startTime.set(res.startTime.get());
        this.endTime.set(res.endTime.get());
        this.projectName.set(res.projectName.get());
        this.resourcesProviderId.set(res.resourcesProviderId.get());
        this.status.set(res.status.get());
        this.children.setAll(res.children);
    }

    /**
     * Copy constructor which adapts status to newStatus
     *
     * @param res       GtsReservation to be copied
     * @param newStatus Status that must be used to override res.status
     */
    public GtsXmlReservation(GtsXmlReservation res, Status newStatus) {
        this.id.set(res.id.get());
        this.startTime.set(res.startTime.get());
        this.endTime.set(res.endTime.get());
        this.projectName.set(res.projectName.get());
        this.resourcesProviderId.set(res.resourcesProviderId.get());
        this.status.set(newStatus);
        this.children.setAll(res.children);
    }

    @XmlElement
    public Integer getId() {
        return id.get();
    }

    void setId(Integer id) {
        this.id.set(id);
    }

    @XmlJavaTypeAdapter(UnixEpochToZonedDateTimeAdapter.class)
    public ZonedDateTime getStartTime() {
        return startTime.get();
    }

    void setStartTime(ZonedDateTime startTime) {
        this.startTime.set(startTime);
    }

    @XmlJavaTypeAdapter(UnixEpochToZonedDateTimeAdapter.class)
    public ZonedDateTime getEndTime() {
        return endTime.get();
    }

    void setEndTime(ZonedDateTime endTime) {
        this.endTime.set(endTime);
    }

    @XmlElement
    public String getProjectName() {
        return projectName.get();
    }

    void setProjectName(String projectName) {
        this.projectName.set(projectName);
    }

    @XmlElement(name = "resourceProviderId")
    public String getResourcesProviderId() {
        return resourcesProviderId.get();
    }

    void setResourcesProviderId(String resourcesProviderId) {
        this.resourcesProviderId.set(resourcesProviderId);
    }

    public StringProperty resourcesProviderIdProperty() {
        return resourcesProviderId;
    }

    @XmlElement
    public Status getStatus() {
        return status.get();
    }

    public void setStatus(Status status) {
        this.status.set(status);
    }

    @XmlElement
    public ObservableList<GtsXmlReservation> getChildren() {
        return children;
    }

    public void setChildren(List<GtsXmlReservation> children) {
        this.children.setAll(children);
    }

    public enum Status {
        RESERVED,
        ACTIVATING,
        ACTIVE,
        DEACTIVATING,
        DEACTIVED,
        RESERVING,
        RELEASING,
        FAILURE,

        /*
        NOT a GTS status, but it indicates that the reservation does no longer exist in the GTS system
         */
        DELETED
    }

    public IntegerProperty idProperty() {
        return id;
    }

    public ObjectProperty<ZonedDateTime> startTimeProperty() {
        return startTime;
    }

    public ObjectProperty<ZonedDateTime> endTimeProperty() {
        return endTime;
    }

    public StringProperty projectNameProperty() {
        return projectName;
    }

    public ObjectProperty<Status> statusProperty() {
        return status;
    }

    public static void copy(GtsXmlReservation target, GtsXmlReservation source) {
        if (!Objects.equals(target.getId(), source.getId()))
            throw new IllegalStateException("Copying info between objects with different ID's is not supported. (and is probably a bug).");
        target.startTime.set(source.startTime.get());
        target.endTime.set(source.endTime.get());
        target.projectName.set(source.projectName.get());
        target.resourcesProviderId.set(source.resourcesProviderId.get());
        target.status.set(source.status.get());
        target.children.setAll(source.children);
    }
}
