/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package eu.dnetlib.espas.sos.client;

import static eu.dnetlib.espas.sos.client.SOSRequestManager._logger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;

/**
 *
 * @author gathanas
 */
public class TimePeriodConstraint {
   private Date fromDate = null;
   private Date toDate = null;
   private long fromSecs = 0;
   private long toSecs = TimeUnit.DAYS.toSeconds(1);
   private String timeConstraintRepresentation = null;
   
    public TimePeriodConstraint() {
    }

    /** This constructor is used when resubmitting request based on previous submissions
    */
    public TimePeriodConstraint(String timeConstraint) {
        this.timeConstraintRepresentation = timeConstraint;
    }

    
   public Date getFromDate() {
      return fromDate;
   }

   public void setFromDate(Date fromDate) {
      this.fromDate = fromDate;
   }

   public Date getToDate() {
      return toDate;
   }

   public void setToDate(Date toDate) {
      this.toDate = toDate;
   }

   public int getFromSecs() {
      return (int) fromSecs;
   }

   public void setFromSecs(int fromSecs) {
      this.fromSecs = fromSecs;
   }

   public int getToSecs() {
      return (int) toSecs;
   }

   public void setToSecs(int toSecs) {
      this.toSecs = toSecs;
   }

   /** A string representation of the given time constraint in the form of
    * (FromDate - ToDate)|(FromDate|ToDate) # (FromSec - ToSec)|(FromSec|ToSec)
    */
   public String toString() {
      String result = "";
      String datePart = "";
      String secPart = "";
      SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
      if (fromDate != null && toDate != null) {
         datePart = dateFormat.format(fromDate) + " - " + dateFormat.format(toDate);
      } else {
         datePart = (fromDate != null ? dateFormat.format(fromDate) : (toDate != null ? dateFormat.format(toDate) : ""));
      }
      if (fromSecs != 0 && toSecs != 0) {
         secPart = fromSecs + " - " + toSecs;
      } else {
         secPart = "" + (fromSecs != 0 ? fromSecs : (toSecs != 0 ? toSecs : ""));
      }
      if (!datePart.isEmpty()) {
         result += datePart;
      }
      if (!secPart.isEmpty()) {
         result += " # " + secPart;
      }
      return result;
   }

    Collection<? extends String> getTimeFilterEncodings() throws ParseException {
//      @todo add implementation code here
//       temporalFilter=om:phenomenonTime,2014-02-01T00:00:00Z/2014-02-03T00:00:00Z
        Set<String> dateTimeConstraints = new TreeSet<String>();
        if (timeConstraintRepresentation != null) {
            dateTimeConstraints.add(timeConstraintRepresentation);
        } 
        else {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
            SimpleDateFormat normDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
            Date tempDate;

//      default value in case of no datetime constraint is empty value; this is used to avoid setting of time filter in sos getResult request
            String datePart = "";
            Date normFromDate = fromDate != null ? normDateFormat.parse(normDateFormat.format(fromDate)) : null;
            // till the end of the toDay
            Date normToDate = toDate != null ? new Date(normDateFormat.parse(normDateFormat.format(toDate)).getTime() + TimeUnit.SECONDS.toMillis(fromSecs)) : null;

            if (fromDate != null && toDate != null) {
                if (toDate.compareTo(fromDate) >= 0) {
//            if from or to sec are set
                    long daySeconds = TimeUnit.DAYS.toSeconds(1);
                    if (toSecs != TimeUnit.DAYS.toSeconds(1) || fromSecs != 0) {
                        for (tempDate = normFromDate; tempDate.compareTo(normToDate) <= 0; tempDate = new Date(tempDate.getTime() + TimeUnit.DAYS.toMillis(1))) {
                            datePart = "om:phenomenonTime,";

                            Date tmpFromDate = new Date(tempDate.getTime() + TimeUnit.SECONDS.toMillis(fromSecs));
                            tmpFromDate = tmpFromDate.compareTo(fromDate) >= 0 ? tmpFromDate : fromDate;

                            Date tmpToDate = new Date(tempDate.getTime() + TimeUnit.SECONDS.toMillis(toSecs));
                            tmpToDate = tmpToDate.compareTo(toDate) >= 0 ? toDate : tmpToDate;

                            if (tmpFromDate.before(tmpToDate)) {
                                datePart += dateFormat.format(tmpFromDate) + "/" + dateFormat.format(tmpToDate);
                                dateTimeConstraints.add(datePart);
                            }
                        }
                    } //            if from sec and to sec are not set
                    else {
                        datePart = "om:phenomenonTime," + dateFormat.format(fromDate) + "/" + dateFormat.format(toDate);
                        dateTimeConstraints.add(datePart);
                    }
                } else {
                    _logger.error("The specified date/time constraints are fault!  From date:" + fromDate + " [" + fromSecs + "] to date :" + toDate.toString() + " [" + toSecs + "]");
                }

            } else if (fromDate != null || toDate != null) {
                datePart = (fromDate != null ? dateFormat.format(new Date(normFromDate.getTime() + TimeUnit.SECONDS.toMillis(fromSecs))) + "/"
                        + dateFormat.format(new Date(normFromDate.getTime() + TimeUnit.SECONDS.toMillis(toSecs)))
                        : (toDate != null ? dateFormat.format(new Date(normToDate.getTime() + TimeUnit.SECONDS.toMillis(fromSecs))) + "/"
                                + dateFormat.format(new Date(normToDate.getTime() + TimeUnit.SECONDS.toMillis(toSecs))) : ""));

                if (!datePart.isEmpty()) {
                    datePart = "om:phenomenonTime," + datePart;
                }

                dateTimeConstraints.add(datePart);
            } else {
                dateTimeConstraints.add("");
            }
        }

        return dateTimeConstraints;
    }
   
    public TimePeriodConstraint filterConstraint(Date startTime, Date endTime) throws ParseException{
        TimePeriodConstraint newConstraint = new TimePeriodConstraint();
        newConstraint.fromSecs = this.fromSecs;
        newConstraint.toSecs = this.toSecs;
        
        Date maxStartDate = (fromDate.before(startTime))?startTime:fromDate;
        Date minEndDate = (toDate.before(endTime))?toDate:endTime;
        
        if(maxStartDate.before(minEndDate)){
            newConstraint.setFromDate(maxStartDate);
            newConstraint.setToDate(minEndDate);
        }
        else
            return null;
         
        newConstraint.getTimeFilterEncodings();
        
        return newConstraint;
    }
}
