package com.baselet.element;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.baselet.control.basics.geom.DimensionDouble;
import com.baselet.control.enums.ElementStyle;
import com.baselet.element.facet.Facet;
import com.baselet.element.facet.PropertiesParserState;

/**
 * The PropertiesParser analyzes the Properties and the Facets of a GridElement and handles AUTORESIZE
 * The Facets typically manipulates the DrawHandler state by executing the drawing methods (e.g. printing the main-text of the element, transforming -- to a horizontal line, ...)
 *
 * A summary of the process is the following:
 * 1. Do a complete parser run (without drawing anything) to calculate the textblock height and possibly start the AUTORESIZE calculation.
 * 2. The First-Run Facets get parsed and applied in order of their PriorityEnum value (this reduces the size of the remaining properties for the Second Run)
 * 3. The common content of the element is drawn (e.g. the border) (therefore this must happen AFTER parsing the First-Run Facets because they can change the bg-color and so on)
 * 4. The remaining properties are parsed and the Second-Run Facets are applied.
 */
public class PropertiesParser {

	public static void parsePropertiesAndHandleFacets(NewGridElement element, PropertiesParserState state) {
		List<String> propertiesText = element.getPanelAttributesAsList();
		doPreparsing(element, state, propertiesText); // at first handle autoresize (which possibly changes elementsize) and calc the textblock size
		parseFacets(element, state, propertiesText, true);
	}

	private static void doPreparsing(NewGridElement element, PropertiesParserState state, List<String> propertiesText) {
		state.resetValues(element.getRealSize(), state.getTotalTextBlockHeight(), false); // assume certain values and disable drawing for the preparsing step
		parseFacets(element, state, propertiesText, false);

		if (state.getElementStyle() == ElementStyle.AUTORESIZE) { // only in case of autoresize element, calculate the elementsize
			double width = state.getCalculatedElementWidth();
			double height = state.getTextPrintPosition() - state.getDrawer().textHeightMax(); // subtract 1xtextheight to avoid making element too high (because the print-text pos is always on the bottom)
			element.handleAutoresize(new DimensionDouble(width, height), state.getAlignment().getHorizontal());
		}

		double textblockHeight = state.getTextPrintPosition() - state.getBuffer().getTop();
		state.resetValues(element.getRealSize(), textblockHeight, true); // now that the element size and textblock height is known, the state is reset once again with enabled drawing
	}

	private static void parseFacets(NewGridElement element, PropertiesParserState state, List<String> propertiesText, boolean drawMetaDrawer) {
		List<String> propertiesAfterFirstRun = parseFacets(state.getSettings().getFacetsForFirstRun(), propertiesText, state); // must be before element.drawCommonContent (because bg=... and other settings are set here)
		element.resetMetaDrawerAndDrawCommonContent(state, drawMetaDrawer); // draw common content like border around classes
		parseFacets(state.getSettings().getFacetsForSecondRun(), propertiesAfterFirstRun, state); // iterate over propertiestext and draw text and resolve second-run facets
	}

	private static List<String> parseFacets(List<? extends Facet> facets, List<String> properties, PropertiesParserState state) {
		Map<Facet, List<String>> facetUsageMap = new HashMap<Facet, List<String>>();
		for (Facet f : facets) { // at parsing start every facet has an empty usage list
			facetUsageMap.put(f, new ArrayList<String>());
		}

		List<String> unusedProperties = new ArrayList<String>(properties);
		for (Iterator<String> iter = unusedProperties.iterator(); iter.hasNext();) {
			String line = iter.next();
			for (Facet f : facets) {
				if (f.checkStart(line, state)) {
					f.handleLine(line, state);
					facetUsageMap.get(f).add(line);
					iter.remove();
					break; // once a facet has consumed a line, no other facet can
				}
			}
		}
		for (Facet f : facets) {
			f.parsingFinished(state, facetUsageMap.get(f));
		}
		return unusedProperties;
	}
}
