package ca.concordia.cssanalyser.migration.topreprocessors;

import java.util.ArrayList;
import java.util.List;

import ca.concordia.cssanalyser.analyser.duplication.DuplicationDetector;
import ca.concordia.cssanalyser.analyser.duplication.items.Item;
import ca.concordia.cssanalyser.analyser.duplication.items.ItemSet;
import ca.concordia.cssanalyser.analyser.duplication.items.ItemSetList;
import ca.concordia.cssanalyser.cssmodel.StyleSheet;
import ca.concordia.cssanalyser.cssmodel.declaration.Declaration;
import ca.concordia.cssanalyser.cssmodel.declaration.ShorthandDeclaration;
import ca.concordia.cssanalyser.cssmodel.selectors.Selector;
import ca.concordia.cssanalyser.migration.topreprocessors.mixin.MixinMigrationOpportunity;

public abstract class PreprocessorMigrationOpportunitiesDetector<T> {
	
	private final StyleSheet styleSheet;
	
	protected abstract MixinMigrationOpportunity<T> getNewPreprocessorSpecificOpportunity(Iterable<Selector> forSelectors);

	public PreprocessorMigrationOpportunitiesDetector(StyleSheet styleSheet) {
		this.styleSheet = styleSheet;
	}
	
	public StyleSheet getStyleSheet() {
		return this.styleSheet;
	}

	public List<? extends MixinMigrationOpportunity<T>> findMixinOpportunities() {
		
		// Remove intra-selector dependencies!
		StyleSheet styleSheetWithRemovedDependencies = this.styleSheet.getStyleSheetWithIntraSelectorDependenciesRemoved();
		
		// Apply FP-Growth on property duplications
		DuplicationDetector duplicationDetector = new DuplicationDetector(styleSheetWithRemovedDependencies);
		duplicationDetector.findPropertyDuplications();
	
		List<ItemSetList> itemSetLists = duplicationDetector.fpGrowth(2, false);
			
		List<MixinMigrationOpportunity<T>> mixinMigrationOpportunities = new ArrayList<>();
			
		/*
		 * Each of the item sets is an opportunity.
		 * Because each of them consist of a list of selectors having declarations with the same properties 
		 */
		for (ItemSetList itemSetList : itemSetLists) {
			
			for (ItemSet itemSet : itemSetList) {
				
				MixinMigrationOpportunity<T> opportunity = getNewPreprocessorSpecificOpportunity(itemSet.getSupport());
				mixinMigrationOpportunities.add(opportunity);
				
				// Declarations in a item have the same property
				for (Item item : itemSet) {
					List<Declaration> declarationsToAdd = new ArrayList<>();
					/*
					 * Check if all of the declarations are virtual shorthand,
					 * in this case, we add individual declarations instead 
					 */
					boolean allVirtual = true;
					// This loop does two things! 
					for (Declaration d : item) {
						if (d instanceof ShorthandDeclaration && !((ShorthandDeclaration)d).isVirtual()) {
							allVirtual = false;
						}
						if (itemSet.supportContains(d.getSelector()))
							declarationsToAdd.add(d);
					}
					// What if all of them are single or multi-valued? you need an extra check
					if (ShorthandDeclaration.isShorthandProperty(declarationsToAdd.get(0).getProperty()) && allVirtual) {
						ShorthandDeclaration referenceVirtualShorthand = (ShorthandDeclaration)declarationsToAdd.get(0);
						for (Declaration referenceIndividual : referenceVirtualShorthand.getIndividualDeclarations()) {
							List<Declaration> individualDeclarationsToAdd = new ArrayList<>();
							individualDeclarationsToAdd.add(referenceIndividual);
							String referenceVirtualShorthandProperty = referenceIndividual.getProperty();
							for (int i = 1; i < declarationsToAdd.size(); i++) {
								ShorthandDeclaration virtualShorthand = (ShorthandDeclaration)declarationsToAdd.get(i);
								Declaration individualForThisProperty = 
										virtualShorthand.getIndividualDeclarationForProperty(referenceVirtualShorthandProperty);
								individualDeclarationsToAdd.add(individualForThisProperty);
							}
							opportunity.addDeclarationsWithTheSameProperty(individualDeclarationsToAdd);
						}
					} else { // If not all the declarations are virtual shorthands
						opportunity.addDeclarationsWithTheSameProperty(declarationsToAdd);	
					}
				}
			}
		}
		
		return mixinMigrationOpportunities;
		
	}
}

@@ -104,16 +104,38 @@
 il.List;
+%0Aimport java.util.Set;
 %0A%0Aimport
@@ -824,18 +824,17 @@
 or%3CT%3E %7B%0A
-%09
 %0A
+
 %09private
@@ -863,18 +863,17 @@
 eSheet;%0A
-%09
 %0A
+
 %09protect
@@ -1097,18 +1097,17 @@
 eet;%0A%09%7D%0A
-%09
 %0A
+
 %09public 
@@ -1245,19 +1245,17 @@
 ies() %7B%0A
-%09%09
 %0A
+
 %09%09// Rem
@@ -1405,19 +1405,17 @@
 oved();%0A
-%09%09
 %0A
+
 %09%09// App
@@ -1606,18 +1606,17 @@
 ions();%0A
-%09
 %0A
+
 %09%09List%3CI
@@ -1682,20 +1682,17 @@
 false);%0A
-%09%09%09
 %0A
+
 %09%09List%3CM
@@ -1769,20 +1769,17 @@
 st%3C%3E();%0A
-%09%09%09
 %0A
+
 %09%09/*%0A%09%09 
@@ -1930,16 +1930,52 @@
  %0A%09%09 */%0A
+%09%09System.out.println(itemSetLists);%0A
 %09%09for (I
@@ -2015,20 +2015,17 @@
 ists) %7B%0A
-%09%09%09
 %0A
+
 %09%09%09for (
@@ -2057,21 +2057,17 @@
 List) %7B%0A
-%09%09%09%09
 %0A
+
 %09%09%09%09Mixi
@@ -2220,13 +2220,9 @@
 y);%0A
-%09%09%09%09
 %0A
+
 %09%09%09%09
@@ -2573,17 +2573,16 @@
  things!
- 
 %0A%09%09%09%09%09fo
@@ -3639,17 +3639,16 @@
 operty =
- 
 %0A%09%09%09%09%09%09%09
@@ -4048,17 +4048,16 @@
 sToAdd);
-%09
 %0A%09%09%09%09%09%7D%0A
@@ -4071,19 +4071,17 @@
 %09%09%7D%0A%09%09%7D%0A
-%09%09
 %0A
+
 %09%09return
@@ -4110,16 +4110,14 @@
 nities;%0A
-%09%09
 %0A%09%7D%0A%7D%0A

Remove unnecessary println