bigtop-master/bigtop-data-generators/bigpetstore-data-generator/src/main/java/org/apache/bigtop/datagenerators/bigpetstore/generators/products/ProductCategoryBuilder.java
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.bigtop.datagenerators.bigpetstore.generators.products;

import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import org.apache.bigtop.datagenerators.bigpetstore.Constants;
import org.apache.bigtop.datagenerators.bigpetstore.datamodels.PetSpecies;
import org.apache.bigtop.datagenerators.bigpetstore.datamodels.Product;
import org.apache.bigtop.datagenerators.bigpetstore.datamodels.inputs.ProductCategory;
import org.apache.bigtop.datagenerators.bigpetstore.generators.products.rules.AlwaysTrueRule;
import org.apache.bigtop.datagenerators.bigpetstore.generators.products.rules.NotRule;
import org.apache.bigtop.datagenerators.bigpetstore.generators.products.rules.OrRule;
import org.apache.bigtop.datagenerators.bigpetstore.generators.products.rules.Rule;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

public class ProductCategoryBuilder
{
	String categoryLabel;
	Set<PetSpecies> applicableSpecies;
	Boolean triggerTransaction;
	Double dailyUsageRate;
	Double amountUsedPerPetAverage;
	Double amountUsedPerPetVariance;
	Double triggerTransactionRate;
	Double triggerPurchaseRate;
	List<Rule> exclusionRules;
	Map<String, Collection<ProductFieldValue>> productFieldValues;
	Double basePrice;
	List<Product> products;

	public ProductCategoryBuilder()
	{
		applicableSpecies = Sets.newHashSet();

		dailyUsageRate = 0.0;
		amountUsedPerPetAverage = 0.0;
		amountUsedPerPetVariance = 0.0;
		triggerTransactionRate = 0.0;
		triggerPurchaseRate = 0.0;
		triggerTransaction = false;
		categoryLabel = null;
		exclusionRules = new Vector<Rule>();
		productFieldValues = Maps.newHashMap();
		basePrice = 1.0;
		products = Lists.newArrayList();
	}

	public void setCategory(String category)
	{
		this.categoryLabel = category;
	}

	public void setTriggerTransaction(Boolean triggerTransaction)
	{
		this.triggerTransaction = triggerTransaction;
	}

	public void setDailyUsageRate(Double dailyUsageRate)
	{
		this.dailyUsageRate = dailyUsageRate;
	}

	public void setAmountUsedPetPetAverage(Double baseAmountUsedAverage)
	{
		this.amountUsedPerPetAverage = baseAmountUsedAverage;
	}

	public void setAmountUsedPetPetVariance(Double baseAmountUsedVariance)
	{
		this.amountUsedPerPetVariance = baseAmountUsedVariance;
	}

	public void setTriggerTransactionRate(Double triggerTransactionRate)
	{
		this.triggerTransactionRate = triggerTransactionRate;
	}

	public void setTriggerPurchaseRate(Double triggerPurchaseRate)
	{
		this.triggerPurchaseRate = triggerPurchaseRate;
	}

	public void addApplicableSpecies(PetSpecies species)
	{
		this.applicableSpecies.add(species);
	}

	public void addProduct(Product product)
	{
		products.add(product);
	}

	public void addExclusionRule(Rule rule)
	{
		this.exclusionRules.add(rule);
	}

	public void addPropertyValues(String fieldName, ProductFieldValue ... values)
	{
		this.productFieldValues.put(fieldName,  Arrays.asList(values));
	}

	public void setBasePrice(double basePrice)
	{
		this.basePrice = basePrice;
	}


	protected List<Product> generateProducts()
	{
		Rule combinedRules = new NotRule(new AlwaysTrueRule());
		if(exclusionRules.size() == 1)
		{
			combinedRules = exclusionRules.get(0);
		}
		else if(exclusionRules.size() > 1)
		{
			 combinedRules = new OrRule(exclusionRules.toArray(new Rule[] {}));
		}

		Iterator<Product> productIterator = new ProductIterator(productFieldValues, combinedRules,
				basePrice, categoryLabel);

		while(productIterator.hasNext())
		{
			products.add(productIterator.next());
		}

		return products;
	}

	public void validateProducts()
	{
		for(Product product : products)
		{
			if(!product.getFieldNames().contains(Constants.PRODUCT_CATEGORY))
			{
				throw new IllegalStateException("Product must have field " + Constants.PRODUCT_CATEGORY);
			}

			if(!product.getFieldNames().contains(Constants.PRODUCT_QUANTITY))
			{
				throw new IllegalStateException("Product must have field " + Constants.PRODUCT_QUANTITY);
			}

			if(!product.getFieldNames().contains(Constants.PRODUCT_PRICE))
			{
				throw new IllegalStateException("Product must have field " + Constants.PRODUCT_PRICE);
			}

			if(!product.getFieldNames().contains(Constants.PRODUCT_UNIT_PRICE))
			{
				throw new IllegalStateException("Product must have field " + Constants.PRODUCT_UNIT_PRICE);
			}
		}
	}

	public ProductCategory build()
	{
		List<Product> products = generateProducts();

		Set<String> fieldNames = Sets.newHashSet();
		for(Product product : products)
		{
			fieldNames.addAll(product.getFieldNames());
		}

		return new ProductCategory(categoryLabel, applicableSpecies, fieldNames, triggerTransaction,
				dailyUsageRate, amountUsedPerPetAverage, amountUsedPerPetVariance, triggerTransactionRate,
					triggerPurchaseRate, products);
	}
}
