/*
 * Copyright (C) 2017 John Garner <[email protected]>
 *
 * 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 com.pikatimer.timing;

import com.pikatimer.race.Race;
import com.pikatimer.race.RaceDAO;
import com.pikatimer.util.Pace;
import javafx.beans.Observable;
import javafx.beans.binding.StringBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.util.Callback;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.GenericGenerator;

/**
 *
 * @author John Garner <[email protected]>
 */
@Entity
@DynamicUpdate
@Table(name="race_segment")
public class Segment implements Comparable<Segment>{
    private final IntegerProperty IDProperty = new SimpleIntegerProperty(); // split_id
    private Race race; // race_id
    private Integer startSplitID; // 
    private Integer endSplitID; 
    private final StringProperty segmentName = new SimpleStringProperty(); 
    private final StringProperty endSplitStringProperty = new SimpleStringProperty();
    private final StringProperty startSplitStringProperty = new SimpleStringProperty();
    private final StringProperty distanceStringProperty = new SimpleStringProperty("0");
    
    private Pace customPace;
    private BooleanProperty useCustomPace = new SimpleBooleanProperty(false);
    private BooleanProperty hideOnResults = new SimpleBooleanProperty(false);
    
    
    public Segment(Race r){

        setRace(r);
    }
    
    public Segment() {

    }
   public static Callback<Segment, Observable[]> extractor() {
        return (Segment s) -> new Observable[]{s.segmentName,s.endSplitStringProperty,s.startSplitStringProperty,s.distanceStringProperty};
    }
   
    @Id
    @GenericGenerator(name="segment_id" , strategy="increment")
    @GeneratedValue(generator="segment_id")
    @Column(name="SEGMENT_ID")
    public Integer getID() {
        return IDProperty.getValue(); 
    }
    public void setID(Integer id) {
        IDProperty.setValue(id);
    }
    public IntegerProperty idProperty() {
        return IDProperty; 
    }
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "RACE_ID",nullable=false)
    public Race getRace() {
        return race;
    }
    public void setRace(Race r) {
        race=r;
    }
   
    @Column(name="SEGMENT_NAME")
    public String getSegmentName() {
        return segmentName.getValueSafe();
    }
    public void setSegmentName(String n) {
        segmentName.setValue(n);
    }
    public StringProperty segmentNameProperty() {
        return segmentName;
    }
    
    @Column(name = "START_SPLIT_ID",nullable=false)
    public Integer getStartSplitID() {
        return startSplitID;
    }
    public void setStartSplitID(Integer id) {
        startSplitID = id;
    }
    @Transient
    public Split getStartSplit() {
        return RaceDAO.getInstance().getSplitByID(startSplitID);
    }
    public void setStartSplit(Split s) {
        if (s != null) {
            System.out.println("Segment.setStartSplit: " + s.getID());
            startSplitID=s.getID();
            startSplitStringProperty.unbind();
            startSplitStringProperty.bind(s.splitNameProperty());
            
            checkSplitOrder();
            
            updateDistanceStringProperty();

        } else {
            System.out.println("Segment.setStartSplit: null"); 
        }
    }
    public StringProperty startSplitStringProperty() {
        if ( ! startSplitStringProperty.isBound() && endSplitID != null && getStartSplit() != null) startSplitStringProperty.bind(getStartSplit().splitNameProperty());
        return startSplitStringProperty; 
    }
    
    @Column(name = "END_SPLIT_ID",nullable=false)
    public Integer getEndSplitID() {
        return endSplitID;
    }
    public void setEndSplitID(Integer id) {
        endSplitID = id;
    }
    
    
    @Column(name="HIDDEN")
    public Boolean getHidden() {
        return hideOnResults.getValue();
    }
    public void setHidden(Boolean n) {
        hideOnResults.setValue(n);
    }
    public BooleanProperty hiddenProperty() {
        return hideOnResults;
    }
    
    @Column(name="use_custom_pace")
    public Boolean getUseCustomPace() {
        return useCustomPace.getValue();
    }
    public void setUseCustomPace(Boolean n) {
        useCustomPace.setValue(n);
    }
    public BooleanProperty useCustomPaceProperty() {
        return useCustomPace;
    }
    
    @Enumerated(EnumType.STRING)
    @Column(name="pace_unit")
    public Pace getCustomPace() {
        return customPace;
    }
    public void setCustomPace(Pace p) {
        customPace = p;
    }
    
    
    @Transient
    public Split getEndSplit() {
        return RaceDAO.getInstance().getSplitByID(endSplitID);
    }
    public void setEndSplit(Split s) {
        if (s != null) {
            System.out.println("Segment.setEndSplit: " + s.getID());
            endSplitID=s.getID();
            endSplitStringProperty.unbind();
            endSplitStringProperty.bind(s.splitNameProperty());
            checkSplitOrder();
            updateDistanceStringProperty();
        } else {
            System.out.println("Segment.setEndSplit: null"); 
        }
    }
    public StringProperty endSplitStringProperty() {
        if ( ! endSplitStringProperty.isBound() && endSplitID != null && getEndSplit() != null) endSplitStringProperty.bind(getEndSplit().splitNameProperty());
        return endSplitStringProperty; 
    }
    
    
    
    
    
    
    @Transient
    public Integer getEndSplitPosition(){
        return getEndSplit().getPosition();
    }
    @Transient
    public Integer getStartSplitPosition(){
        return getStartSplit().getPosition();
    }
    public StringProperty distanceStringProperty(){
        updateDistanceStringProperty();
        return distanceStringProperty;
    }
    
    @Transient
    public Float getSegmentDistance(){
        return getEndSplit().getSplitDistance().subtract(getStartSplit().getSplitDistance()).abs().floatValue();
    }
    private void updateDistanceStringProperty(){
        if (getEndSplit() != null && getStartSplit() != null) {
            distanceStringProperty.unbind();
            distanceStringProperty.bind(new StringBinding(){
                {
                super.bind(getEndSplit().splitDistanceProperty(),getStartSplit().splitDistanceProperty());
                }
                @Override
                protected String computeValue() {
                    return getEndSplit().getSplitDistance().subtract(getStartSplit().getSplitDistance()).abs().toPlainString().concat(" " + getEndSplit().getSplitDistanceUnits().toShortString());
                }
            });
            //distanceStringProperty.setValue(getEndSplit().getSplitDistance().subtract(getStartSplit().getSplitDistance()).abs().toPlainString().concat(" " + getEndSplit().getSplitDistanceUnits().toShortString()));
        } else {
            distanceStringProperty.unbind();
            distanceStringProperty.setValue("0");
        }
            
    }

    private void checkSplitOrder() {
        if (getEndSplit() != null && getStartSplit() != null && getStartSplit().getSplitDistance().compareTo(getEndSplit().getSplitDistance()) > 0 ) {
            // Switch them
            Integer t = endSplitID;
            endSplitID = startSplitID;
            startSplitID = t; 
            
            endSplitStringProperty.unbind();
            endSplitStringProperty.bind(getEndSplit().splitNameProperty());
            
            startSplitStringProperty.unbind();
            startSplitStringProperty.bind(getStartSplit().splitNameProperty());
        }
    }

    @Override
    public int compareTo(Segment other) {
        // compare end split
        if (this.getEndSplit() != null && other.getEndSplit() == null) return 1;
        if (this.getEndSplit() == null && other.getEndSplit() != null) return -1;
        if (this.getEndSplitPosition() > other.getEndSplitPosition()) return 1;
        if (this.getEndSplitPosition() < other.getEndSplitPosition()) return -1;
        
        // compare start split
        if (this.getStartSplit() != null && other.getStartSplit() == null) return 1;
        if (this.getStartSplit() == null && other.getStartSplit() != null) return -1;
        if (this.getStartSplitPosition() > other.getStartSplitPosition()) return 1;
        if (this.getStartSplitPosition() < other.getStartSplitPosition()) return -1;
        
        return 0;
    }
    
    
}