/*
 * Copyright (C) 2003-2008 eXo Platform SAS.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Affero 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 org.exoplatform.services.jcr.ext.classify.impl;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;

import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Session;

import org.apache.commons.lang.StringUtils;
import org.exoplatform.commons.utils.ISO8601;
import org.exoplatform.container.xml.InitParams;
import org.exoplatform.container.xml.PropertiesParam;
import org.exoplatform.services.jcr.ext.classify.NodeClassifyPlugin;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;



/*
 * Created by The eXo Platform SAS
 * Author : Hoa.Pham
 *          hoa.pham@exoplatform.com
 * Apr 9, 2008  
 */
/**
 * The Class DateTimeClassifyPlugin.
 */
@Deprecated
public class DateTimeClassifyPlugin extends NodeClassifyPlugin {

  /** The Constant MONTHS. */
  private static final int MONTHS = 12;

  /** The template date time. */
  private String templateDateTime;
  
  /** The property date time. */
  private String propertyDateTime;
  
  /** The start date time. */
  private Calendar startDateTime;
  
  /** The end date time. */
  private Calendar endDateTime;  
  
  /** The increment. */
  private int increment;
  
  /** The increment type. */
  private char incrementType;

  /** The log. */
  private static Log log = ExoLogger.getLogger(DateTimeClassifyPlugin.class);
  
  /**
   * Instantiates a new date time classify plugin.
   * 
   * @param initParams the init params
   */
  public DateTimeClassifyPlugin(final InitParams initParams) {
    try {
      PropertiesParam propertiesParam = initParams.getPropertiesParam("plugin-params");
      String templDateTimeParam = propertiesParam.getProperty("DateTimeTemplate");       
      String startDateTimeParam = propertiesParam.getProperty("StartTime");
      String endDateTimeParam = propertiesParam.getProperty("EndTime");            
      propertyDateTime = propertiesParam.getProperty("DateTimePropertyName");      
      if ("".equals(propertyDateTime)) propertyDateTime = "exo:dateCreated";      
      templateDateTime = getWellTemplDateTime(templDateTimeParam);      
      startDateTime = getCalendar(startDateTimeParam);
      endDateTime = getCalendar(endDateTimeParam);           
      setIncrement();        
    } catch (Exception e) {
      log.error("Error when perform DateTimeClassifyPlugin: ", e);
    }    
  }

  /* (non-Javadoc)
   * @see org.exoplatform.services.jcr.ext.classify.NodeClassifyPlugin#classifyChildrenNode(javax.jcr.Node)
   */
  public void classifyChildrenNode(Node parent) throws Exception {
    Session session = parent.getSession();        
    for (NodeIterator nodes = parent.getNodes(); nodes.hasNext();) {
      Node node = nodes.nextNode();      
      Calendar calNode = node.getProperty(propertyDateTime).getDate();
      if ((calNode.before(startDateTime)) || (calNode.after(endDateTime))) continue;             
      Node currentNode = createNewDateTimeNode(parent, getDateTimeStructured(templateDateTime, calNode));      
      String srcPath = node.getPath();
      String destPath = currentNode.getPath() + "/" + node.getName();
      session.move(srcPath, destPath);
      session.save();              
    }      
  }

  /**
   * Gets the date time structured.
   * 
   * @param templDateTime the templ date time
   * @param calendar the calendar
   * 
   * @return the date time structured
   */
  private String getDateTimeStructured(String templDateTime, Calendar calendar) {    
    int year =  calendar.get(Calendar.YEAR),
    month =  calendar.get(Calendar.MONTH) + 1,   
    woy =  calendar.get(Calendar.WEEK_OF_YEAR),
    wom =  calendar.get(Calendar.WEEK_OF_MONTH),
    dom =  calendar.get(Calendar.DAY_OF_MONTH),
    dow =  calendar.get(Calendar.DAY_OF_WEEK),
    startYear = startDateTime.get(Calendar.YEAR),
    startMonth = startDateTime.get(Calendar.MONTH);
    switch (incrementType) {
    case 'Y':              
      int n = (year - startYear) / (increment + 1);
      year = n * (increment + 1) + startYear;  
      break;      
    case 'M':      
      if (year != startYear) startMonth = 1;
      int m = (month - startMonth) / (increment + 1);
      month = m * (increment + 1) + startMonth;        
      break;     
    default: break;
    }        
    templDateTime = templDateTime.replace("YYYY", Integer.toString(year))
    .replace("MM", Integer.toString(month))
    .replace("WW", Integer.toString(woy))
    .replace("ww", Integer.toString(wom))
    .replace("DD", Integer.toString(dom))
    .replace("dd", Integer.toString(dow));          
    String expr = templDateTime.substring(templDateTime.indexOf("{") + 1 , templDateTime.indexOf("}"));    
    templDateTime = templDateTime.replace(expr, operateExpression(expr))
    .replace("#", "").replace("{", "")
    .replace("}", "");          
    return templDateTime;
  }  


  /**
   * Operate expression.
   * 
   * @param expression the expression
   * 
   * @return the string
   */
  private String operateExpression(String expression) {        
    String [] items = StringUtils.split(expression, "+");
    int rel = Integer.parseInt(items[0]) + Integer.parseInt(items[1]);
    int endTime = endDateTime.get(Calendar.YEAR);
    if ((incrementType == 'Y') && (rel > endTime)) rel = endTime;
    else if ((incrementType == 'M') && (rel > MONTHS)) rel = MONTHS;        
    String result  = Integer.toString(rel);    
    return result; 
  }

  /**
   * Creates the new date time node.
   * 
   * @param parentNode the parent node
   * @param path the path
   * 
   * @return the node
   * 
   * @throws Exception the exception
   */
  private Node createNewDateTimeNode(Node parentNode, String path) throws Exception {  
    String [] items = path.split("/");    
    Node currNode = null;
    for (int i = 0; i < items.length; i++) { 
      try { 
        currNode = parentNode.getNode(items[i]); 
      } catch (Exception e) { currNode = parentNode.addNode(items[i]); }
      parentNode = currNode;
    }       
    return currNode;
  }    

  /**
   * Gets the well templ date time.
   * 
   * @param templ the templ
   * 
   * @return the well templ date time
   */
  private String getWellTemplDateTime(String templ) {
    templ = templ.replace(" ", "");
    List<String> temp = new ArrayList<String>();    
    String [] items = templ.split("/");
    for (String item : items) {
      if (item.contains("-")) {
        if (item.contains("#")) {
          String subStr = item.substring(item.indexOf("+") + 1 , item.indexOf("}"));
          try {
            Integer.parseInt(subStr);
            item = item.replace("+", "").replace(subStr, "");
            if ((!"YYYY-#{YYYY}".equals(item)) && (!"MM-#{MM}".equals(item))) {
              templ = "";
              break;
            } 
          } catch (Exception e) {
            templ = "";
            break;
          } 
        } else {
          String [] subItems = item.split("-");
          for (String subItem : subItems) temp.add(subItem);          
        }        
      } else if (!isValidField(item)) {
        templ = "";        
        break;
      }
    }
    return templ;
  }

  /**
   * Checks if is valid field.
   * 
   * @param field the field
   * 
   * @return true, if is valid field
   */
  private boolean isValidField(String field) {
    if ((!"YYYY".equals(field)) && (!"MM".equals(field)) && (!"WW".equals(field.toUpperCase())) && (!"DD".equals(field.toUpperCase())))
      return false;    
    return true;   
  }


  /**
   * Gets the calendar.
   * 
   * @param datetime the datetime
   * 
   * @return the calendar
   */
  private Calendar getCalendar(String datetime) {
    Calendar calendar = new GregorianCalendar();
    try {
      calendar = ISO8601.parse(datetime);
      return calendar;
    } catch (Exception e) {
      log.error("Error when perform getCalendar: ", e);
    } 
    return null;
  }

  /**
   * Sets the increment.
   */
  private void setIncrement() {
    String subStr = templateDateTime.substring(templateDateTime.indexOf("+") + 1 , templateDateTime.indexOf("}"));
    increment = Integer.parseInt(subStr);
    incrementType = templateDateTime.charAt(templateDateTime.indexOf("{") + 1);        
  }  

}
