/* Generated By:JJTree: Do not edit this line. AST_Stats.java Version 4.3 */
/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=false,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package com.everdata.parser;

import java.util.ArrayList;

import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogram;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogram.Interval;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramBuilder;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
import org.elasticsearch.search.aggregations.bucket.histogram.HistogramBuilder;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsBuilder;
import org.elasticsearch.search.aggregations.metrics.avg.AvgBuilder;
import org.elasticsearch.search.aggregations.metrics.cardinality.CardinalityBuilder;
import org.elasticsearch.search.aggregations.metrics.max.MaxBuilder;
import org.elasticsearch.search.aggregations.metrics.min.MinBuilder;
import org.elasticsearch.search.aggregations.metrics.sum.SumBuilder;
import org.elasticsearch.search.aggregations.metrics.valuecount.ValueCountBuilder;


import com.everdata.command.CommandException;
import com.everdata.command.Field;
import com.everdata.command.Function;

public class AST_Stats extends SimpleNode {
	public static class Bucket{		
		public String bucketField;
		public boolean desc = true;
		public boolean keyOrder = false;
		public boolean script = false;		
		
		public int type = 0;
		public static final int TERM = 0;
		public static final int TERMWITHCARD = 3;
		public static final int HISTOGRAM = 1;
		public static final int DATEHISTOGRAM = 2;
	}

	private ArrayList<AggregationBuilder<?>> buckets = null;
	AbstractAggregationBuilder[] internalReport = null;	
	ArrayList<Bucket> bucketFields = new ArrayList<Bucket>();
	ArrayList<Function> funcs = new ArrayList<Function>();
	ArrayList<Integer> mincounts = new ArrayList<Integer>();
	ArrayList<Integer> limits = new ArrayList<Integer>();
	ArrayList<String> timespans = new ArrayList<String>();
	ArrayList<Integer> spans = new ArrayList<Integer>();
	//ArrayList<String> statsFields = new ArrayList<String>();
	
	
	
	public ArrayList<Bucket> bucketFields(){
		return bucketFields; 
	}
	
	public ArrayList<Function> statsFields(){
		return funcs;
	}

	public AST_Stats(int id) {
		super(id);
	}

	public AST_Stats(CommandParser p, int id) {
		super(p, id);
	}
	
	public static AbstractAggregationBuilder newCount(Function func) {
		ValueCountBuilder count;
		count = AggregationBuilders.count(Function.genStatField(func))
					.field(func.field);

		return count;
	}

	public static AbstractAggregationBuilder newSum(Function func) {
		SumBuilder sum;
		if (func.fieldtype == Field.SCRIPT)
			sum = AggregationBuilders.sum(Function.genStatField(func))
					.script(func.field);
		else
			sum = AggregationBuilders.sum(Function.genStatField(func))
					.field(func.field);

		return sum;
	}

	public static AbstractAggregationBuilder newAvg(Function func) {
		AvgBuilder avg;
		if (func.fieldtype == Field.SCRIPT)
			avg = AggregationBuilders.avg(Function.genStatField(func))
					.script(func.field);
		else
			avg = AggregationBuilders.avg(Function.genStatField(func))
					.field(func.field);

		return avg;
	}

	public static AbstractAggregationBuilder newMin(Function func) {
		MinBuilder min;
		if (func.fieldtype == Field.SCRIPT)
			min = AggregationBuilders.min(Function.genStatField(func))
					.script(func.field);
		else
			min = AggregationBuilders.min(Function.genStatField(func))
					.field(func.field);		
		return min;
	}

	public static AbstractAggregationBuilder newMax(Function func) {
		MaxBuilder max;
		if (func.fieldtype == Field.SCRIPT)
			max = AggregationBuilders.max(Function.genStatField(func))
					.script(func.field);
		else
			max = AggregationBuilders.max(Function.genStatField(func))
					.field(func.field);
		return max;
	}
	
	public static AbstractAggregationBuilder newCard(Function func) {
		CardinalityBuilder max;
		if (func.fieldtype == Field.SCRIPT)
			max = AggregationBuilders.cardinality(Function.genStatField(func))
					.script(func.field);
		else
			max = AggregationBuilders.cardinality(Function.genStatField(func))
					.field(func.field);
		return max;
	}
	
	public static TermsBuilder newTermsBucket(String name, int limit, String field, int mincount, boolean script) {
		TermsBuilder d = AggregationBuilders.terms(name).size(limit).minDocCount(mincount);
		
		return script? d.script(field): d.field(field);
	}
	
	public static DateHistogramBuilder newDateHistogram(String name, String field, String interval, int mincount, boolean script) {
		DateHistogramBuilder d = AggregationBuilders.dateHistogram(name).interval(new Interval(interval)).minDocCount(mincount);
		
		return script? d.script(field): d.field(field);
	}

	public static HistogramBuilder newHistogram(String name, String field, int interval, int mincount, boolean script) {
		HistogramBuilder d = AggregationBuilders.histogram(name).field(field).interval(interval).minDocCount(mincount);
		
		return script? d.script(field): d.field(field);
	}
	
	private void traverseAST() {

		for (Node n : children) {
			if (n instanceof AST_ByIdentList) {
				AST_ByIdentList byStmt = ((AST_ByIdentList) n);
				
				for(int idx = 0; idx < byStmt.byList.size(); idx++ ){
					
					
					Bucket b = new Bucket();
					
								
					b.bucketField = byStmt.byList.get(idx).name;
					b.desc = byStmt.byList.get(idx).desc;
					b.keyOrder = byStmt.byList.get(idx).keyorder;
					b.script = byStmt.byList.get(idx).script;
					bucketFields.add(b);
				}
				
			} else if (n instanceof AST_StatsFunc) {
				
				((AST_StatsFunc) n).func.statsField = Function.genStatField( ((AST_StatsFunc) n).func ) ;
				funcs.add(((AST_StatsFunc) n).func);
			}
		}
	}
	
	public void setBucketLimit(int idx, long limit){
		if(buckets.get(idx) instanceof TermsBuilder)
			((TermsBuilder)buckets.get(idx)).size((int) limit);
	}
	
	public static final int DEFAULT_LIMIT = 50;
	public static final int DEFAULT_LIMIT_CARD = -1;
	public static final int DEFAULT_MINICOUNT = 1;

	private AbstractAggregationBuilder[] genAggregation() throws CommandException {

		traverseAST();

		
		
		//生成bucket列表
		buckets = new ArrayList<AggregationBuilder<?>>();
		
		for(int i = 0 ; i < bucketFields.size(); i++){
			AggregationBuilder<?> bucket = null;
			int mincount = DEFAULT_MINICOUNT;
			int limit = DEFAULT_LIMIT;
			if(limits.size() > i)
				limit = limits.get(i);
			if(mincounts.size() > i)
				mincount = mincounts.get(i);
			
			if( spans.size() > i && spans.get(i) != 0 ){
				
				Histogram.Order order;
				
				order = (bucketFields.get(i).desc)?(
					 bucketFields.get(i).keyOrder?Histogram.Order.KEY_DESC: Histogram.Order.COUNT_DESC
				):(
					bucketFields.get(i).keyOrder?Histogram.Order.KEY_ASC:Histogram.Order.COUNT_ASC
				);
				
				bucketFields.get(i).type = Bucket.DATEHISTOGRAM;
				
				bucket = newHistogram("statsWithBy", bucketFields.get(i).bucketField, spans.get(i), mincount,bucketFields.get(i).script).order(order);
			}else if( timespans.size() > i && !timespans.get(i).equals("NA") ){
				
				DateHistogram.Order order;
				
				order =(bucketFields.get(i).desc)?(
					 bucketFields.get(i).keyOrder?DateHistogram.Order.KEY_DESC:DateHistogram.Order.COUNT_DESC
				):(
					bucketFields.get(i).keyOrder?DateHistogram.Order.KEY_ASC: DateHistogram.Order.COUNT_ASC
				);
				bucketFields.get(i).type = Bucket.DATEHISTOGRAM;
				bucket = newDateHistogram("statsWithBy", bucketFields.get(i).bucketField, timespans.get(i), mincount, bucketFields.get(i).script).order(order);
				
			}else{
				Terms.Order order;
				
				order = (bucketFields.get(i).desc)?(
					bucketFields.get(i).keyOrder? Terms.Order.term(false):Terms.Order.count(false)
				):(
					bucketFields.get(i).keyOrder?Terms.Order.term(true):Terms.Order.count(true)
				);
				
					
				bucketFields.get(i).type = (limit == DEFAULT_LIMIT_CARD)?Bucket.TERMWITHCARD:Bucket.TERM;
				
				bucket = newTermsBucket("statsWithBy", (limit == DEFAULT_LIMIT_CARD)?DEFAULT_LIMIT:limit, bucketFields.get(i).bucketField, mincount, bucketFields.get(i).script).order(order);				
			}

			buckets.add(bucket);
			
		}
		ArrayList<AbstractAggregationBuilder> stats = new ArrayList<AbstractAggregationBuilder>();
		
		//生成functions列表		
		for (Function func : funcs) {
			AbstractAggregationBuilder function = null;
			switch (func.type) {
			case Function.COUNT:
				function = newCount(func);
				break;
			case Function.SUM:
				function = newSum(func);
				break;
			case Function.AVG:
				function = newAvg(func);
				break;
			case Function.MIN:
				function = newMin(func);
				break;
			case Function.MAX:
				function = newMax(func);
				break;
			case Function.DC:
				function = newCard(func);
				break;
			}
			stats.add(function);
			
			//需要根据统计字段排序
			if(func.order != 0 && buckets.size() > 0){
				
				boolean asc = func.order == 1 ? true:false;
								
				switch(bucketFields.get(0).type){
				case Bucket.TERM :
				case Bucket.TERMWITHCARD:
					((TermsBuilder)buckets.get(0)).order(Terms.Order.aggregation(Function.genStatField(func), asc));
					break;
				case Bucket.HISTOGRAM :
					((HistogramBuilder)buckets.get(0)).order(Histogram.Order.aggregation(Function.genStatField(func), asc));
					break;
				case Bucket.DATEHISTOGRAM :
					((DateHistogramBuilder)buckets.get(0)).order(DateHistogram.Order.aggregation(Function.genStatField(func), asc));
					break;
				}
			}
		}		

		if(buckets.size() == 0){			
			return stats.toArray(new AbstractAggregationBuilder[stats.size()]);
		}else{
			
			AggregationBuilder<?> prevBucket = null;
			
			for(AggregationBuilder<?> bucket: buckets){
				if(prevBucket == null){
					for(AbstractAggregationBuilder func: stats){
						bucket.subAggregation(func);						
					}
				}else{
					bucket.subAggregation(prevBucket);
				}			
				prevBucket = bucket;
			}
			
			AbstractAggregationBuilder[] bucketArray = new AbstractAggregationBuilder[1];
			bucketArray[0] = prevBucket;
			
			return bucketArray;			
		}


	}

	public AbstractAggregationBuilder[] getStats() throws CommandException {

		if (internalReport == null)
			internalReport = genAggregation();

		return internalReport;
	}

}
/*
 * JavaCC - OriginalChecksum=663713222972f6d3f2e7821e2216d7f2 (do not edit this
 * line)
 */