/*
 * 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.spatial;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
import org.apache.log4j.Logger;

/**
 *
 * @author gathanas
 */
public class TimePeriodConstraint {
   private static final Logger _logger = Logger.getLogger(TimePeriodConstraint.class);

   private Date fromDate = null;
   private Date toDate = null;
   private long fromSecs = 0;
   private long toSecs = TimeUnit.DAYS.toSeconds(1);
   private String timeConstraintRepresentation = null;
   private Collection<Date[]> dateTimeFilters;
   
    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;
      this.dateTimeFilters=null;
   }

   public Date getToDate() {
      return toDate;
   }

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

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

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

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

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

   /** 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;
   }

   public Collection<Date[]> getTimeFilter() throws ParseException{
      Collection<Date[]> results = this.dateTimeFilters;
      
      if(results==null){
         results = new LinkedList<Date[]>();
         SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");

         for(String timePeriod : getTimeFilterEncodings())
            if(!timePeriod.isEmpty()){
               Date fDate=null, tDate=null;
               String[] dateTimes = timePeriod.split("/");
               try{
               if(dateTimes.length>1){
                  fDate = dateFormat.parse(dateTimes[0]);
                  tDate = dateFormat.parse(dateTimes[1]);
               }
               else{
                  fDate = dateFormat.parse(dateTimes[0]);
                  tDate = fDate;
               }
               results.add(new Date[]{fDate,tDate});

               }catch(ParseException pex){
                  _logger.error("Parse exception occured while processing datetime from TimePeriodConstraint",pex);
                  continue;
               }
            }
         this.dateTimeFilters = results;
      }
      
      return results;
   }
   
   public 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:ssZ");
            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 = "";

                            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 = 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))) : ""));

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

        return dateTimeConstraints;
    }
}
