package it.mice.voila.runtime.springmvc.taglibs;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import javax.servlet.jsp.JspException;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.context.MessageSource;
import org.springframework.web.servlet.tags.form.AbstractHtmlElementTag;
import org.springframework.web.servlet.tags.form.TagWriter;

public class InternalFrameTag extends AbstractHtmlElementTag {
	/**
	 */
	private static final long serialVersionUID = 1L;

	private static final String STYLE_PRIMARY = "primary";
	private static final String STYLE_DEFAULT = "default";
	private static final String STYLE_TAB_CONTENT = "tab-content";

	private String frameId = null;
	private String style = STYLE_PRIMARY;
	private String legendLabel = null;
	private boolean collapsable = false;
	private boolean closeable = false;
	private boolean goTopLink = false;
	private String initialState = "expanded";
	private String modes = null;
	private boolean useFieldset = true;

	private String cmdLabel1;
	private String cmdAction1;
	private String cmdTitle1;
	private String cmdLabel2;
	private String cmdAction2;
	private String cmdTitle2;
	private String cmdLabel3;
	private String cmdAction3;
	private String cmdTitle3;
	private String cmdLabel4;
	private String cmdAction4;
	private String cmdTitle4;

	private String toolBoxAlign;
	private boolean customCollapseIcon;

	private TagWriter tagWriter;
	private Collection<FrameCommandTag> commandList = new ArrayList<FrameCommandTag>();

	public boolean isStyleTabContent() {
		return STYLE_TAB_CONTENT.equals(getStyle());
	}

	public String getModes() {
		return modes;
	}

	public void setModes(String modes) {
		this.modes = modes;
	}

	public String getStyle() {
		return style;
	}

	public void setStyle(String style) {
		this.style = style;
	}

	public String getCmdLabel1() {
		return cmdLabel1;
	}

	public void setCmdLabel1(String cmdLabel1) {
		this.cmdLabel1 = cmdLabel1;
	}

	public String getCmdAction1() {
		return cmdAction1;
	}

	public void setCmdAction1(String cmdAction1) {
		this.cmdAction1 = cmdAction1;
	}

	public String getCmdTitle1() {
		return cmdTitle1;
	}

	public void setCmdTitle1(String cmdTitle1) {
		this.cmdTitle1 = cmdTitle1;
	}

	public String getCmdLabel2() {
		return cmdLabel2;
	}

	public void setCmdLabel2(String cmdLabel2) {
		this.cmdLabel2 = cmdLabel2;
	}

	public String getCmdAction2() {
		return cmdAction2;
	}

	public void setCmdAction2(String cmdAction2) {
		this.cmdAction2 = cmdAction2;
	}

	public String getCmdTitle2() {
		return cmdTitle2;
	}

	public void setCmdTitle2(String cmdTitle2) {
		this.cmdTitle2 = cmdTitle2;
	}

	public String getCmdLabel3() {
		return cmdLabel3;
	}

	public void setCmdLabel3(String cmdLabel3) {
		this.cmdLabel3 = cmdLabel3;
	}

	public String getCmdAction3() {
		return cmdAction3;
	}

	public void setCmdAction3(String cmdAction3) {
		this.cmdAction3 = cmdAction3;
	}

	public String getCmdTitle3() {
		return cmdTitle3;
	}

	public void setCmdTitle3(String cmdTitle3) {
		this.cmdTitle3 = cmdTitle3;
	}

	public String getCmdLabel4() {
		return cmdLabel4;
	}

	public void setCmdLabel4(String cmdLabel4) {
		this.cmdLabel4 = cmdLabel4;
	}

	public String getCmdAction4() {
		return cmdAction4;
	}

	public void setCmdAction4(String cmdAction4) {
		this.cmdAction4 = cmdAction4;
	}

	public String getCmdTitle4() {
		return cmdTitle4;
	}

	public void setCmdTitle4(String cmdTitle4) {
		this.cmdTitle4 = cmdTitle4;
	}

	public Collection<FrameCommandTag> getCommandList() {
		return commandList;
	}

	public void setCommandList(Collection<FrameCommandTag> commandList) {
		this.commandList = commandList;
	}

	public String getFrameId() {
		return frameId;
	}

	public void setFrameId(String frameId) {
		this.frameId = frameId;
	}

	public String getLegendLabel() {
		return legendLabel;
	}

	public void setLegendLabel(String legendLabel) {
		this.legendLabel = legendLabel;
	}

	public String getInitialState() {
		return initialState;
	}

	public void setInitialState(String initialState) {
		this.initialState = initialState;
	}

	public boolean isUseFieldset() {
		return useFieldset;
	}

	public void setUseFieldset(boolean useFieldset) {
		this.useFieldset = useFieldset;
	}

	public boolean isCollapsable() {
		return collapsable;
	}

	public void setCollapsable(boolean collapsable) {
		this.collapsable = collapsable;
	}

	public boolean isCloseable() {
		return closeable;
	}

	public void setCloseable(boolean closeable) {
		this.closeable = closeable;
	}

	public boolean isGoTopLink() {
		return goTopLink;
	}

	public void setGoTopLink(boolean goTopLink) {
		this.goTopLink = goTopLink;
	}

	@Override
	protected int writeTagContent(TagWriter tagWriter) throws JspException {
		this.tagWriter = tagWriter;

		MessageSource messageSource = getRequestContext().getMessageSource();

		processFrameCommands(messageSource);

		writeFieldsetAndLegend(messageSource);

		if (TagUtils.isBootstrapTheme()) {
			tagWriter.startTag("div");
			tagWriter.writeAttribute("id", "IFB" + getFrameId());
			tagWriter.writeAttribute(CLASS_ATTRIBUTE, "box-body");
			if (isCollapsable() && getInitialState() != null && getInitialState().equalsIgnoreCase("collapsed")) {
				tagWriter.writeAttribute(STYLE_ATTRIBUTE, "display: none;");
			}
			tagWriter.forceBlock();
			if (isStyleTabContent()) {
				String label = TagUtils.getMessage(getRequestContext(), evaluate("legendLabel", legendLabel));
				label = getDisplayString(label);
				writeBoxTitle(label);
			}
		} else {
			tagWriter.startTag("div");
			tagWriter.writeAttribute("id", "IFB" + getFrameId());
			if (isCollapsable() && getInitialState() != null && getInitialState().equalsIgnoreCase("collapsed")) {
				tagWriter.writeAttribute(CLASS_ATTRIBUTE, "layerFrameBodyCollapsed");
			} else {
				tagWriter.writeAttribute(CLASS_ATTRIBUTE, "layerFrameBody");
			}
			tagWriter.forceBlock();
		}

		return EVAL_BODY_INCLUDE;
	}

	private void processFrameCommands(MessageSource messageSource) throws JspException {
		processFrameCommand(messageSource, getCmdLabel1(), getCmdAction1(), getCmdTitle1());
		processFrameCommand(messageSource, getCmdLabel2(), getCmdAction2(), getCmdTitle2());
		processFrameCommand(messageSource, getCmdLabel3(), getCmdAction3(), getCmdTitle3());
		processFrameCommand(messageSource, getCmdLabel4(), getCmdAction4(), getCmdTitle4());
	}

	private void processFrameCommand(MessageSource messageSource, String label, String action, String title)
			throws JspException {

		if (StringUtils.isEmpty(action)) {
			return;
		}
		FrameCommandTag commandBean = new FrameCommandTag();
		commandBean.setAction(evaluate("action", action).toString());
		commandBean.setLabel(TagUtils.getMessage(getRequestContext(), evaluate("label", label)));
		commandBean.setTitle(TagUtils.getMessage(getRequestContext(), evaluate("title", title)));

		getCommandList().add(commandBean);
	}

	private void writeFieldsetAndLegend(MessageSource messageSource) throws JspException {
		if (TagUtils.isBootstrapTheme()) {
			writeBootstrapFieldsetAndLegend(messageSource);
		} else {
			writeStandardFieldsetAndLegend(messageSource);
		}
	}

	private void writeBootstrapFieldsetAndLegend(MessageSource messageSource) throws JspException {
		if (isUseFieldset()) {
			tagWriter.startTag("fieldset");
		} else {
			tagWriter.startTag("div");
		}

		if (StringUtils.isEmpty(getCssClass())) {
			setCssClass("box box-solid box-primary");
		}
		if (isCollapsable() && getInitialState() != null && getInitialState().equalsIgnoreCase("collapsed")) {
			setCssClass(getCssClass() + " collapsed-box");
		}
		tagWriter.writeAttribute("id", "IF" + getFrameId());

		try {
			writeOptionalAttributes(tagWriter);
		} catch (Exception e) {
			logger.debug(e
					+ " raised during internal frame rendering. Probably the frame was used out of a BindingResult object resolution. Ignoring...");
		}

		if (isStyleTabContent()) {
			return;
		}

		String label = TagUtils.getMessage(getRequestContext(), evaluate("legendLabel", legendLabel));
		label = getDisplayString(label);
		if (StringUtils.isEmpty(label) && !isUseFieldset()) {
			return;
		}
		if (isUseFieldset()) {
			tagWriter.startTag("div");
			tagWriter.writeAttribute("id", "le" + getFrameId());
			if (StringUtils.isEmpty(label)) {
				label = "&nbsp;";
			}
		} else {
			tagWriter.startTag("div");
		}
		tagWriter.writeAttribute(CLASS_ATTRIBUTE, "box-header");

		if (!isToolBoxLeftAligned()) {
			writeBoxTitle(label);
		}
		tagWriter.startTag("div");

		if (isToolBoxLeftAligned()) {
			tagWriter.writeAttribute(CLASS_ATTRIBUTE, "box-tools pull-left");
			if (isCollapsable()) {

				writeHeaderWidget("collapse", getInitialState().equalsIgnoreCase("collapsed") ? getPlusCollapseIcon()
						: getMinusCollapseIcon(), null, null, null);
			}
		} else {
			tagWriter.writeAttribute(CLASS_ATTRIBUTE, "box-tools pull-right");
		}
		if (!isToolBoxLeftAligned()) {
			int ctr = 1;
			for (Iterator<FrameCommandTag> i = commandList.iterator(); i.hasNext();) {
				FrameCommandTag tag = i.next();
				processBootstrapCommand(tag, ctr++);
			}
		}
		if (!StringUtils.isEmpty(getModes())) {
			writeModesWidget();
		}

		if (!isToolBoxLeftAligned()) {
			if (isCollapsable()) {
				writeHeaderWidget("collapse", getInitialState().equalsIgnoreCase("collapsed") ? "fa-plus" : "fa-minus",
						null, null, null);
			}
		}

		if (isCloseable()) {
			writeHeaderWidget("remove", "fa-times", null, null, null);
		}

		tagWriter.endTag(true); // div box-tools

		if (isToolBoxLeftAligned()) {
			writeBoxTitle(label);
			int ctr = 1;
			for (Iterator<FrameCommandTag> i = commandList.iterator(); i.hasNext();) {
				FrameCommandTag tag = i.next();
				processBootstrapCommand(tag, ctr++);
			}
		}

		tagWriter.endTag(true); // legend or div
	}

	private void writeBoxTitle(String label) throws JspException {
		tagWriter.startTag("h3");
		tagWriter.writeAttribute(CLASS_ATTRIBUTE, "box-title");
		tagWriter.appendValue(label);
		tagWriter.endTag();
	}

	private void writeModesWidget() throws JspException {
		String[] theModes = getModes().split(" ");
		for (String mode : theModes) {
			writeModeWidget(mode.trim());
		}
	}

	private void writeModeWidget(String mode) throws JspException {
//		<div class="btn-group">
//			<button type="submit"
//				name="button.submit.search?listViewMode=calendar"
//				id="button_submit_search_listViewMode_calendar"
//				class="btn btn-primary btn-sm dropdown-toggle" title="Calendar view mode"
//				data-toggle="dropdown">
//				<i class="fa fa-clock-o"></i>
//				&nbsp;<span class="caret"></span>
//			</button>
//			<ul class="dropdown-menu" role="menu">
//	            <li><a href="search?listViewMode=calendar&listViewModeFor=orderDate" title="Calendar view mode based upon Order Date">per Order Date</a></li>
//	            <li><a href="search?listViewMode=calendar&listViewModeFor=shipDate" title="Calendar view mode based upon Ship Date">per Ship Date</a></li>
//	        </ul>
//      </div>

		boolean hasOneModeFor = false;
		boolean hasMoreModeFor = false;
		int squareBracketStart = mode.indexOf("[");
		int squareBracketEnd = mode.indexOf("]");
		String[] modeFors = null;
		if (squareBracketStart > -1 && squareBracketEnd > -1) {
			String modeFor = mode.substring(squareBracketStart + 1, squareBracketEnd);
			modeFors = modeFor.split(",");
			mode = mode.substring(0, squareBracketStart);
			hasOneModeFor = modeFors.length == 1;
			hasMoreModeFor = modeFors.length > 1;
		}

		String name = "button.submit.search?listViewMode=" + mode
				+ (hasOneModeFor ? "&listViewModeFor=" + modeFors[0] : "");
		tagWriter.startTag("div");
		tagWriter.writeAttribute("class", "btn-group");

		tagWriter.startTag("button");
		tagWriter.writeAttribute("type", "submit");
		tagWriter.writeAttribute("name", name);
		tagWriter.writeAttribute("id", "button_submit_search_listViewMode_" + mode);
		tagWriter.writeAttribute("class", "btn btn-primary btn-sm");
		tagWriter.writeAttribute("title",
				getRequestContext().getMessage(mode + ".view.mode.title", mode + " view mode"));

		if (hasMoreModeFor) {
			tagWriter.writeAttribute("data-toggle", "dropdown");
		}

		String icon = "fa-" + mode;
		if ("list".equals(mode)) {
			icon = "fa-table";
		}
		if ("calendar".equals(mode)) {
			icon = "fa-clock-o";
		}
		if ("map".equals(mode)) {
			icon = "fa-globe";
		}
		if ("kanban".equals(mode)) {
			icon = "fa-columns";
		}
		if ("chart".equals(mode)) {
			icon = "fa-bar-chart";
		}
		tagWriter.startTag("i");
		tagWriter.writeAttribute("class", "fa " + icon);
		tagWriter.endTag(true); // i

		if (hasMoreModeFor) {
			tagWriter.appendValue("&nbsp;");
			tagWriter.startTag("span");
			tagWriter.writeAttribute("class", "caret");
			tagWriter.endTag(true); // span
		}

		tagWriter.endTag(true); // button

		if (hasMoreModeFor) {
			tagWriter.startTag("ul");
			tagWriter.writeAttribute("class", "dropdown-menu dropdown-menu-right");
			tagWriter.writeAttribute("role", "menu");

			for (String modeFor : modeFors) {
				String trimmedModeFor = modeFor.trim();
				String fieldLabel = resolveFieldLabel(trimmedModeFor.replaceAll(":", ""));
//	            <li><a href="search?listViewMode=calendar&listViewModeFor=orderDate" title="Calendar view mode based upon Order Date">per Order Date</a></li>
				tagWriter.startTag("li");
				tagWriter.startTag("a");
				tagWriter.writeAttribute("href", "search?listViewMode=" + mode + "&listViewModeFor=" + trimmedModeFor);
				tagWriter.writeAttribute("title", getRequestContext().getMessage("view.mode.for.title",
						new String[] { fieldLabel }, mode + " view mode on " + trimmedModeFor));
				tagWriter.appendValue(getRequestContext().getMessage("view.mode.for.label", new String[] { fieldLabel },
						"for " + trimmedModeFor));

				tagWriter.endTag(true); // a
				tagWriter.endTag(true); // li
			}

			tagWriter.endTag(true); // ul
		}

		tagWriter.endTag(true); // div.btn-group
	}

	private String resolveFieldLabel(String trimmedModeFor) {
		// Try by prepending label.getFrameId() to the field name
		String result = getRequestContext().getMessage("label." + getFrameId() + "." + trimmedModeFor, trimmedModeFor);
		return result;
	}

	private void writeHeaderWidget(String widget, String icon, String label, String title, String onClick)
			throws JspException {
		// <button type="button" class="btn btn-primary btn-sm"
		// data-widget="collapse"><i class="fa fa-minus"></i></button>
		tagWriter.startTag("button");
		tagWriter.writeAttribute("type", "button");
		if (isToolBoxLeftAligned()) {
			if (!StringUtils.isEmpty(onClick)) {
				tagWriter.writeAttribute("class", "btn btn-primary btn-sm pull-right frameButton rightFrameButton");
			} else {
				tagWriter.writeAttribute("class", "btn btn-primary btn-sm pull-right frameButton");
			}
		} else {
			tagWriter.writeAttribute("class", "btn btn-primary btn-sm");
		}
		if (!StringUtils.isEmpty(title)) {
			tagWriter.writeAttribute("title", title);
		}
		if (!StringUtils.isEmpty(widget)) {
			tagWriter.writeAttribute("data-widget", widget);
		}
		if (!StringUtils.isEmpty(onClick)) {
			tagWriter.writeAttribute("onClick", onClick);
		}
		tagWriter.writeAttribute("id", getFrameId() + "_" + widget);

		if (!StringUtils.isEmpty(icon)) {
			// <i class="fa fa-minus"></i>
			tagWriter.startTag("i");
			tagWriter.writeAttribute("class", "fa " + icon);
			tagWriter.endTag(true); // i
		}

		if (!StringUtils.isEmpty(label)) {
			tagWriter.appendValue(label);
			;
		}

		tagWriter.endTag(true); // button
	}

	private void writeStandardFieldsetAndLegend(MessageSource messageSource) throws JspException {
		if (isUseFieldset()) {
			tagWriter.startTag("fieldset");
		} else {
			tagWriter.startTag("div");
			setCssClass(TagUtils.safePrepend(getCssClass(), "fieldset"));
		}
		tagWriter.writeAttribute("id", "IF" + getFrameId());

		try {
			writeOptionalAttributes(tagWriter);
		} catch (Exception e) {
			logger.debug(e
					+ " raised during internal frame rendering. Probably the frame was used out of a BindingResult object resolution. Ignoring...");
		}

		String label = TagUtils.getMessage(getRequestContext(), evaluate("legendLabel", legendLabel));
		label = getDisplayString(label);
		if (StringUtils.isEmpty(label) && !isUseFieldset()) {
			return;
		}
		if (isUseFieldset()) {
			tagWriter.startTag("legend");
			tagWriter.writeAttribute("id", "le" + getFrameId());
			if (StringUtils.isEmpty(label)) {
				tagWriter.writeAttribute(CLASS_ATTRIBUTE, "empty");
				label = "&nbsp;";
			}
		} else {
			tagWriter.startTag("h3");
			tagWriter.writeAttribute(CLASS_ATTRIBUTE, "legend");
		}
		if (isCollapsable()) {
			tagWriter.writeAttribute(ONCLICK_ATTRIBUTE, "switchFrameLayout('" + getFrameId() + "', true)");
		}
		tagWriter.appendValue(label);
		tagWriter.endTag();

		writeFieldsetBanner(messageSource);
	}

	private void writeFieldsetBanner(MessageSource messageSource) throws JspException {
		tagWriter.startTag("div");
		tagWriter.writeAttribute(CLASS_ATTRIBUTE, "fieldsetBanner");
		tagWriter.forceBlock();

		int ctr = 1;
		for (Iterator<FrameCommandTag> i = commandList.iterator(); i.hasNext();) {
			FrameCommandTag tag = i.next();
			processCommand(tag, ctr++);
		}

		writeCollapseableCommand(messageSource);
		writeCloseableCommand(messageSource);
		tagWriter.endTag();
		writeClearDiv();
	}

	private void writeClearDiv() throws JspException {
		tagWriter.startTag("div");
		tagWriter.writeAttribute(CLASS_ATTRIBUTE, "cleardiv");
		tagWriter.appendValue("&nbsp;");
		tagWriter.endTag();
	}

	private void writeCloseableCommand(MessageSource messageSource) throws JspException {
		if (isCloseable()) {
			String msgClose = messageSource.getMessage("label.frame.close", TagUtils.EMPTY_ARRAY,
					getRequestContext().getLocale());
			TagUtils.safeWrite(pageContext, "|&nbsp;");
			tagWriter.startTag("a");
			tagWriter.writeAttribute("id", "IFCI" + getFrameId());
			tagWriter.writeAttribute("href", "javascript: closeFrame('" + getFrameId() + "')");
			tagWriter.writeAttribute(CLASS_ATTRIBUTE, "close");
			tagWriter.writeAttribute(TITLE_ATTRIBUTE, msgClose);
			tagWriter.appendValue(msgClose);
			tagWriter.endTag();
			TagUtils.safeWrite(pageContext, "&nbsp;");
		}
	}

	private void writeCollapseableCommand(MessageSource messageSource) throws JspException {
		if (isCollapsable()) {
			tagWriter.startTag("span");
			tagWriter.writeAttribute("id", "IFTI" + getFrameId() + "_c");
			tagWriter.writeAttribute(CLASS_ATTRIBUTE, "container");
			tagWriter.forceBlock();
			tagWriter.endTag();

			if (TagUtils.isMessageCode(getTitle())) {
				setTitle(messageSource.getMessage(TagUtils.getMessageCode(getTitle()), TagUtils.EMPTY_ARRAY, getTitle(),
						getRequestContext().getLocale()));
			}
			String trottleClass;
			if (getInitialState() != null && getInitialState().equalsIgnoreCase("collapsed")) {
				trottleClass = "collapsed";
			} else {
				trottleClass = "expanded";
			}

			addComplexAttribute("IFTI" + getFrameId(), "javascript: switchFrameLayout('" + getFrameId() + "', true)",
					messageSource.getMessage("label.frame.collapseExpand", new String[] { getTitle() },
							getRequestContext().getLocale()),
					messageSource.getMessage("label.frame.collapseExpandTitle", new String[] { getTitle() },
							getRequestContext().getLocale()),
					"trottle " + trottleClass);
		}
	}

	private void addComplexAttribute(String property, String href, String name, String title, String className)
			throws JspException {
		tagWriter.startTag("script");
		tagWriter.writeAttribute("type", "text/JavaScript");

		StringBuffer scriptContent = new StringBuffer("AddLoadEvent(function() { initInternalFrameField(\"");

		scriptContent.append(property).append("\"");

		if (href != null) {
			scriptContent.append(", \"").append(href).append("\"");
		} else {
			scriptContent.append(",undefined ");
		}
		if (name != null) {
			scriptContent.append(", \"").append(name).append("\"");
		} else {
			scriptContent.append(",undefined ");
		}
		if (title != null) {
			scriptContent.append(", \"").append(StringEscapeUtils.escapeJavaScript(title)).append("\"");
		} else {
			scriptContent.append(",undefined ");
		}
		if (className != null) {
			scriptContent.append(", \"").append(className).append("\"");
		} else {
			scriptContent.append(",undefined ");
		}
		scriptContent.append(");");

		tagWriter.appendValue(scriptContent.toString());

		tagWriter.appendValue("})");
		tagWriter.endTag();
	}

	private void processCommand(FrameCommandTag tag, int ctr) throws JspException {
		if (tag.getAction().startsWith("javascript:")) {
			tagWriter.startTag("span");
			tagWriter.writeAttribute("id", "IFTI" + getFrameId() + ctr + "_c");
			tagWriter.writeAttribute(CLASS_ATTRIBUTE, "container");
			tagWriter.forceBlock();
			tagWriter.endTag();
			addComplexAttribute("IFTI" + getFrameId() + ctr, tag.getAction(), tag.getLabel(), tag.getTitle(), null);
		} else {
			TagUtils.safeWrite(pageContext, "|&nbsp;");
			tagWriter.startTag("a");
			tagWriter.writeAttribute("href", tag.getAction());
			tagWriter.writeAttribute(TITLE_ATTRIBUTE, tag.getTitle());
			tagWriter.appendValue(tag.getLabel());
			tagWriter.endTag();
			TagUtils.safeWrite(pageContext, "&nbsp;");
		}
	}

	private void processBootstrapCommand(FrameCommandTag tag, int ctr) throws JspException {
		if (tag.getAction().startsWith("widget:")) {
			String dataWidget = tag.getAction().substring("widget:".length()).trim();
			writeHeaderWidget(dataWidget, null, tag.getLabel(), tag.getTitle(), null);
		} else if (tag.getAction().startsWith("javascript:")) {
			String onClick = tag.getAction().substring("javascript:".length()).trim();
			writeHeaderWidget("command_" + ctr, null, tag.getLabel(), tag.getTitle(), onClick);
		} else {
			if (ctr > 1) {
				TagUtils.safeWrite(pageContext, "|&nbsp;");
			}
			tagWriter.startTag("a");
			tagWriter.writeAttribute("href", tag.getAction());
			tagWriter.writeAttribute(TITLE_ATTRIBUTE, tag.getTitle());
			tagWriter.appendValue(tag.getLabel());
			tagWriter.endTag();
			TagUtils.safeWrite(pageContext, "&nbsp;");
		}
	}

	/**
	 * Closes the '<code>form</code>' block tag and removes the form object name
	 * from the {@link javax.servlet.jsp.PageContext}.
	 */
	@Override
	public int doEndTag() throws JspException {
		MessageSource messageSource = getRequestContext().getMessageSource();
		writeGoTopLink(messageSource);

		tagWriter.endTag();
		tagWriter.endTag();

		return EVAL_PAGE;
	}

	private void writeGoTopLink(MessageSource messageSource) throws JspException {
		if (isGoTopLink()) {
			String goToTopLink = messageSource.getMessage("label.frame.goToTopLink", TagUtils.EMPTY_ARRAY,
					getRequestContext().getLocale());
			String goToTopLinkTitle = messageSource.getMessage("label.frame.goToTopLinkTitle", TagUtils.EMPTY_ARRAY,
					getRequestContext().getLocale());
			tagWriter.startTag("div");
			tagWriter.writeAttribute(CLASS_ATTRIBUTE, "goToTop");
			tagWriter.startTag("a");
			tagWriter.writeAttribute("href", "#content");
			tagWriter.writeAttribute("title", goToTopLinkTitle);
			tagWriter.appendValue(goToTopLink);
			tagWriter.endTag();
			tagWriter.endTag();
		}
	}

	/**
	 * Clears the stored {@link TagWriter}.
	 */
	@Override
	public void doFinally() {
		super.doFinally();

		setCssClass(null);
		this.cmdAction1 = null;
		this.cmdLabel1 = null;
		this.cmdTitle1 = null;
		this.cmdAction2 = null;
		this.cmdLabel2 = null;
		this.cmdTitle2 = null;
		this.cmdAction3 = null;
		this.cmdLabel3 = null;
		this.cmdTitle3 = null;
		this.cmdAction4 = null;
		this.cmdLabel4 = null;
		this.cmdTitle4 = null;
		this.frameId = null;
		this.legendLabel = null;
		this.collapsable = false;
		this.closeable = false;
		this.goTopLink = false;
		this.initialState = "expanded";
		this.useFieldset = true;
		this.commandList = new ArrayList<FrameCommandTag>();
		this.tagWriter = null;
		this.modes = null;
		this.style = STYLE_PRIMARY;
		this.toolBoxAlign = null;
		this.setCustomCollapseIcon(false);
	}

	public String getToolBoxAlign() {
		return toolBoxAlign;
	}

	public void setToolBoxAlign(String toolBoxAlign) {
		this.toolBoxAlign = toolBoxAlign;
	}

	/**
	 * Controlla se si č scelto di avere la tooBox a sinistra invece che a destra.
	 * L'impostazione čuņ essere globale mediante la proprietą frame.toolBox.align
	 * in ApplicationResource o specifica nel frame
	 * 
	 * @author Vittorio Niespolo <vittorio.niespolo@micegroup.it>
	 *
	 * @return
	 */
	private boolean isToolBoxLeftAligned() {
		String globalToolBoxAlign = null;

		try {
			globalToolBoxAlign = getRequestContext().getMessage("frame.toolBox.align");
		} catch (Exception e) {

		}

		if ("left".equals(globalToolBoxAlign) && !"right".equals(getToolBoxAlign())) {
			return true;
		}
		return "left".equals(getToolBoxAlign());
	}

	/**
	 * Ritorna il valore di una properties presente nel file Application.properties
	 * del progetto oppure null se non presente
	 * 
	 * @author Vittorio Niespolo <vittorio.niespolo@micegroup.it>
	 *
	 * @param key
	 * @return
	 */
	public String getProperty(String key) {
		try {
			return getRequestContext().getMessage(key);
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * Ritorna l'icona scelta per il frame collapsabile quando č aperto
	 * 
	 * @author Vittorio Niespolo <vittorio.niespolo@micegroup.it>
	 *
	 * @return
	 */
	public String getMinusCollapseIcon() {
		String minusCollapseIcon = getProperty("frame.collapseIcon.minus");

		if (minusCollapseIcon != null && isCustomCollapseIcon()) {
			return minusCollapseIcon;
		}
		return "fa-minus";
	}

	/**
	 * Ritorna l'icona scelta per il frame collapsabile quando č chiuso
	 * 
	 * @author Vittorio Niespolo <vittorio.niespolo@micegroup.it>
	 *
	 * @return
	 */
	public String getPlusCollapseIcon() {
		String plusCollapseIcon = getProperty("frame.collapseIcon.plus");
		
		if (plusCollapseIcon != null && isCustomCollapseIcon()) {
			return plusCollapseIcon;
		}
		return "fa-plus";
	}

	public boolean isCustomCollapseIcon() {
		return customCollapseIcon;
	}

	public void setCustomCollapseIcon(boolean customCollapseIcon) {
		this.customCollapseIcon = customCollapseIcon;
	}
}
