public interface DocumentManager {

	public abstract com.idega.xformsmanager.business.Document createForm(
			LocalizedStringBean formName, String formType);

	/**
	 * 
	 * @return List of available form components types by category
	 */
	public abstract List<String> getAvailableFormComponentsTypesList(
			ConstComponentCategory category);

	/**
	 * 
	 * @return List of available form components types by datatype
	 */
	public abstract List<ComponentType> getComponentsByDatatype(
			ConstComponentDatatype category);

	/**
	 * opens form by id, and loads all the structure. @see openFormLazy for lazy
	 * loading behavior
	 * 
	 * @param formId
	 * @return
	 */
	public abstract com.idega.xformsmanager.business.Document openForm(
			Long formId);

	/**
	 * opens form by id, but doesn't load all the structure. Loading is deferred
	 * to when necessary (lazy loading)
	 * 
	 * @param formId
	 * @return
	 */
	public abstract com.idega.xformsmanager.business.Document openFormLazy(
			Long formId);
	
	public abstract com.idega.xformsmanager.business.Document openFormLazy(Document xformsDoc);

	/**
	 * opens form by xforms xml, and loads all the structure. @see openFormLazy
	 * for lazy loading behavior
	 * 
	 * @param xformsDoc
	 * @return
	 */
	public abstract com.idega.xformsmanager.business.Document openForm(
			Document xformsDoc);

	/**
	 * used to fix the version of the form that is in flux state (not fixed
	 * state). In other words, it stores the copy of the form of id provided
	 * (formIdToTakeFrom), and generates new form id for it (for static version)
	 * 
	 * @param formIdToTakeFrom
	 *            id of the form to make static version from
	 * @return document of the fixed version form (static)
	 */
	public abstract com.idega.xformsmanager.business.Document takeForm(
			Long formIdToTakeFrom);

	public abstract void setPersistenceManager(
			PersistenceManager persistence_manager);

	public abstract void init(IWMainApplication iwma)
			throws InitializationException;

	public abstract boolean isInited();

	public abstract void setCacheManager(CacheManager cacheManager);

	public abstract void setTransformerService(
			TransformerService transformerService);

	public abstract void setComponentsXforms(Document componentsXforms);

	public abstract void setComponentsXsd(Document componentsXsd);

	public abstract void setFormXformsTemplate(Document formXformsTemplate);
} public class PersistedFormDocument {

	private Document xformsDocument;
	private Long formId;
	private String formType;
	private Integer version;

	private boolean outputReplaced;

	public Document getXformsDocument() {
		return xformsDocument;
	}

	public void setXformsDocument(Document xformsDocument) {
		if (!outputReplaced && IWMainApplication.getDefaultIWMainApplication().getSettings().getBoolean("xforms_idega_output", Boolean.FALSE)) {
			String xformInString = null;
			InputStream xformStream = null;
			try {
				//	Replacing buggy "xf:output" to "idega:output"
				StringWriter sw = new StringWriter();
				XmlUtil.prettyPrintDOM(xformsDocument, sw);
				xformInString = sw.toString();
				xformInString = StringHandler.replace(xformInString, "xf:output", FormManagerUtil.output_tag);
				xformInString = StringHandler.replace(xformInString, "idega:output ref=\".\"", "xf:output ref=\".\"");

				//	Re-building XML document
				xformStream = StringHandler.getStreamFromString(xformInString);
				xformsDocument = XmlUtil.getDocumentBuilder().parse(xformStream);
			} catch (Exception e) {
				Logger.getLogger(getClass().getName()).log(Level.WARNING, "Error converting String to XForm:\n" + xformInString, e);
			} finally {
				IOUtil.close(xformStream);
				outputReplaced = true;
			}
		}

		this.xformsDocument = xformsDocument;
	}

	public Long getFormId() {
		return formId;
	}

	public void setFormId(Long formId) {
		this.formId = formId;
	}

	public String getFormType() {
		return formType;
	}

	public void setFormType(String formType) {
		this.formType = formType;
	}

	public Integer getVersion() {
		return version;
	}

	public void setVersion(Integer version) {
		this.version = version;
	}
} public interface PersistenceManager {
	
	public abstract PersistedFormDocument loadForm(Long formId);
	
	public abstract PersistedFormDocument loadPopulatedForm(
	        String submissionUUID) throws InvalidSubmissionException;
	
	public abstract PersistedFormDocument loadPopulatedForm(
	        String submissionUUID, boolean pdfView) throws InvalidSubmissionException;
	
	public abstract PersistedFormDocument saveForm(FormDocument document)
	        throws IllegalAccessException;
	
	public abstract PersistedFormDocument saveAllVersions(FormDocument document, Long formId)
    	throws IllegalAccessException;
	
	/**
	 * stores document under the storeBasePath specified. This should be the relative path to the
	 * content repository root in use. E.g. if the root is /files then the base path could look like
	 * this: /bpm/forms/
	 * 
	 * @param document
	 * @param storeBasePath
	 * @return
	 * @throws IllegalAccessException
	 */
	public abstract PersistedFormDocument saveForm(FormDocument document,
	        String storeBasePath) throws IllegalAccessException;
	
	public abstract PersistedFormDocument takeForm(Long formId);
	
	public abstract List<Form> getStandaloneForms();
	
	/**
	 * Stores submitted data
	 * 
	 * @param formId
	 *            - not null
	 * @param is
	 *            - not null
	 * @param identifier
	 *            - could be null, some random identifier would be generated
	 * @return submission UUID
	 * @throws IOException
	 */
	public abstract String saveSubmittedData(Long formId, InputStream is,
	        String identifier, boolean finalSubmission, Integer formSubmitter) throws IOException;
	
	/**
	 * @param submissionUUID
	 * @param formId
	 *            - not null
	 * @param is
	 *            - not null
	 * @param identifier
	 *            - could be null, would be generated some random identifier
	 * @return submission id
	 * @throws IOException
	 */
	public abstract String saveSubmittedDataByExistingSubmission(
	        String submissionUUID, Long formId, InputStream is,
	        String identifier, Integer formSubmitter) throws IOException;
	
	/**
	 * set submission to invalid, this is used for saved forms, and this means, that the saved form
	 * cannot be viewed by the submissionUUID. This usually means that the form is already submitted
	 * 
	 * @param submissionUUID
	 * @throws IOException
	 */
	public abstract void invalidateSubmittedDataByExistingSubmission(
	        String submissionUUID);
	
	public abstract List<Submission> getAllStandaloneFormsSubmissions();
	
	public abstract List<Submission> getFormsSubmissions(long formId);
	
	public abstract Submission getSubmission(long submissionId);
} public final class ConstComponentCategory {

	public static final String BASIC = "basic";
	public static final String BUTTONS = "buttons";
	public static final String NON_DISPLAY = "non-display";
	public static final String PLAIN = "plain";
	public static final String AUTOFILL = "autofill";
	private static List<String> components_categories = new ArrayList<String>();
	
	private String components_category;
	
	static {
		components_categories.add(BASIC);
		components_categories.add(BUTTONS);
		components_categories.add(NON_DISPLAY);
		components_categories.add(PLAIN);
		components_categories.add(AUTOFILL);
	}
	
	public ConstComponentCategory(String button_type) {
		
		if(!components_categories.contains(button_type))
			throw new NullPointerException("Provided category not supported: "+button_type);
		
		this.components_category = button_type;
	}
	
	public String getComponentsCategory() {
		return components_category;
	}
	
	public static List<String> getComponentsCategories() {
		return components_categories;
	}
	
	@Override
	public String toString() {
		return "components category set: "+getComponentsCategory();
	}
} public interface FormDocument extends FormComponentContainer {
	
	public abstract void setFormDocumentModified(boolean changed);
	
	public abstract boolean isFormDocumentModified();
	
	public abstract Document getComponentsXml(Locale locale);
	
	public abstract Long getFormId();
	
	public abstract Locale getDefaultLocale();
	
	public abstract FormComponentPage getFormConfirmationPage();
	
	public abstract String generateNewComponentId();
	
	public abstract Element getAutofillModelElement();
	
	public abstract Element getFormDataModelElement();
	
	public abstract Element getFormMainDataInstanceElement();
	
	public abstract Element getSubmissionElement();
	
	public abstract Element getSectionsVisualizationInstanceElement();
	
	public abstract PropertiesDocument getProperties();
	
	public abstract String getFormType();
	
	public abstract LocalizedStringBean getFormTitle();
	
	public abstract Document getXformsDocument();
	
	public abstract DMContext getContext();
	
	/**
	 * @param tagExpression
	 *            xf: prefixed tag expression. E.g. xf:instance
	 * @return created element. This element is not appended anywhere
	 */
	public abstract Element createXFormsElement(String tagExpression);
	
	/**
	 * @param tagExpression
	 *            xf: prefixed tag expression. E.g. idega:setvalue
	 * @return created element. This element is not appended anywhere
	 */
	public abstract Element createIdegaXFormsElement(String tagExpression);
} public class LocalizedStringBean {

	private static final Logger LOGGER = Logger.getLogger(LocalizedStringBean.class.getName());

	private Map<Locale, String> strings;

	public LocalizedStringBean() {
		strings = new HashMap<Locale, String>();
	}

	public LocalizedStringBean(String defaultString) {
		strings = new HashMap<Locale, String>();
		setString(new Locale(Locale.ENGLISH.toString()), defaultString);
	}

	public Set<Locale> getLanguagesKeySet() {
		return strings.keySet();
	}

	/**
	 * if You don't want to change the text, provide text value as null
	 *
	 * @param locale
	 * @param text
	 */
	public void setString(Locale locale, String text) {
		if (locale == null)
			throw new IllegalArgumentException("Locale is not provided");

		strings.put(locale, text);
	}

	public String getString(Locale locale) {
		if (!strings.containsKey(locale)) {
			LOGGER.warning("There are no labels for locale: " + locale + ". Labels exist for locale(s): " + strings.keySet());
		}

		return strings.get(locale);
	}

	public void removeString(Locale locale) {
		strings.remove(locale);
	}

	public void clear() {
		strings.clear();
	}

	@Override
	public String toString() {
		StringBuffer toString = new StringBuffer("LocalizedStringBean:");

		for (Iterator<Locale> iter = strings.keySet().iterator(); iter.hasNext();) {
			Locale locale = iter.next();

			toString.append("\nlocale: ")
			.append(locale.toString())
			.append(" value: ")
			.append(strings.get(locale));
		}

		return toString.toString();
	}
} public class ComponentType {
	
	private String type;
	private List<String> datatypes = new ArrayList<String>();
	private String accessSupport;
	
	public ComponentType() {
		
	}
	
	public ComponentType(String id, String accessSupport) {
		this.type = id;
		this.accessSupport = accessSupport;
	}
	
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
	public List<String> getDatatypes() {
		return datatypes;
	}
	public void setDatatypes(List<String> datatypes) {
		this.datatypes = datatypes;
	}
	public String getAccessSupport() {
		return accessSupport;
	}
	public void setAccessSupport(String accessSupport) {
		this.accessSupport = accessSupport;
	}

} public class ConstComponentDatatype {
	
	public static final String STRING = "string";
	public static final String LIST = "list";
	public static final String FILE = "file";
	public static final String FILES = "files";
	private static List<String> components_datatypes = new ArrayList<String>();
	
	private String datatype;
	
	static {
		components_datatypes.add(STRING);
		components_datatypes.add(LIST);
		components_datatypes.add(FILE);
		components_datatypes.add(FILES);
	}
	
	public ConstComponentDatatype(String datatype) {
		
		if(!components_datatypes.contains(datatype))
			throw new NullPointerException("Provided datatype not supported: " + datatype);
		
		this.datatype = datatype;
	}
	
	public String getDatatype() {
		return datatype;
	}


	public void setDatatype(String datatype) {
		this.datatype = datatype;
	}


	@Override
	public String toString() {
		return "components category set: " + getDatatype();
	}

} @Service
@Scope("singleton")
public class FormComponentFactory {
	
	private Map<String, List<String>> components_tags_classified;
	private static final String type_simple = "type_simple";
	private static final String type_select = "type_select";
	private static final String type_non_display = "type_non_display";
	private static final String type_static = "type_static";
	private static final String type_upload = "type_upload";
	private static final String type_page = "type_page";
	private static final String type_output = "type_output";
	
	public static final String page_type_tag = FormManagerUtil.idegans_case_tag;
	public static final String page_type = "fbc_page";
	public static final String confirmation_page_type = "fbc_confirmation_page";
	public static final String button_type = FormManagerUtil.trigger_tag;
	public static final String fbc_button_area = "fbc_button_area";
	public static final String page_type_thx = "thx_page";
	
	private FormManager formManager;
	
	private FormComponentFactory() {
		
		components_tags_classified = new HashMap<String, List<String>>();
		
		List<String> types = new ArrayList<String>();
		
		types.add("fbc_autofill_name");
		types.add("fbc_autofill_first_name");
		types.add("fbc_autofill_last_name");
		types.add("fbc_autofill_personal_id");
		types.add("fbc_autofill_address");
		types.add("fbc_autofill_phones");
		types.add("fbc_autofill_emails");
		types.add("fbc_autofill_country");
		types.add("fbc_autofill_province");
		types.add("fbc_autofill_city");
		types.add("fbc_autofill_commune");
		types.add("fbc_autofill_postal_code");
		types.add("fbc_identifier_number");
		types.add("fbc_text");
		types.add("fbc_date");
		types.add("fbc_current_date");
		types.add("fbc_textarea");
		types.add("fbc_secret");
		types.add("fbc_email");
		types.add("fbc_upload");
		types.add("xf:input");
		types.add("xf:secret");
		types.add("xf:textarea");
		components_tags_classified.put(type_simple, types);
		
		List<String> non_display_types = new ArrayList<String>();
		non_display_types.add(fbc_button_area);
		non_display_types.add(page_type);
		non_display_types.add(confirmation_page_type);
		components_tags_classified.put(type_non_display, non_display_types);
		
		types = new ArrayList<String>();
		
		types.add("fbc_multiple_select_minimal");
		types.add("xf:select");
		types.add("fbc_single_select_minimal");
		types.add("xf:select1");
		types.add("fbc_multiple_select");
		types.add("fbc_single_select");
		
		components_tags_classified.put(type_select, types);
		
		types = new ArrayList<String>();
		types.add("fbc_static_output");
		types.add("fbc_simple_text");
		types.add("fbc_header_text");
		types.add("fbc_separator");
		
		components_tags_classified.put(type_static, types);
		
		types = new ArrayList<String>();
		types.add("fbc_multiupload");
		components_tags_classified.put(type_upload, types);
		
		types = new ArrayList<String>();
		types.add(page_type_tag);
		types.add(page_type);
		types.add(confirmation_page_type);
		types.add(page_type_thx);
		types.add("save_page");
		components_tags_classified.put(type_page, types);
		
		types = new ArrayList<String>();
		types.add("fbc_text_output");
		components_tags_classified.put(type_output, types);
	}
	
	public FormComponent getFormComponentByType(String componentType) {
		
		FormComponent component = recognizeFormComponent(componentType);
		component.setType(componentType);
		return component;
	}
	
	public FormComponent recognizeFormComponent(String componentType) {
		
		if (isUploadType(componentType))
			return new FormComponentMultiUploadImpl();
		if (isSelectType(componentType))
			return new FormComponentSelectImpl();
		if (isPageType(componentType))
			return new FormComponentPageImpl();
		if (isButtonAreaType(componentType))
			return new FormComponentButtonAreaImpl();
		if (isButtonType(componentType))
			return new FormComponentButtonImpl();
		if (isStaticType(componentType))
			return new FormComponentStaticImpl();
		if (isOutputType(componentType))
			return new FormComponentOutputImpl();
		
		return new FormComponentImpl();
	}
	
	private boolean isUploadType(String componentType) {
		
		return components_tags_classified.get(type_upload).contains(
		    componentType);
	}
	
	private boolean isSelectType(String componentType) {
		
		return components_tags_classified.get(type_select).contains(
		    componentType);
	}
	
	private boolean isPageType(String componentType) {
		
		return components_tags_classified.get(type_page)
		        .contains(componentType);
	}
	
	private boolean isButtonAreaType(String componentType) {
		
		return componentType.equals(fbc_button_area);
	}
	
	private boolean isButtonType(String componentType) {
		
		return componentType.equals(button_type)
		        || ConstButtonType.getAllTypesInStrings().contains(
		            componentType);
	}
	
	private boolean isStaticType(String componentType) {
		
		return components_tags_classified.get(type_static).contains(
		    componentType);
	}
	
	private boolean isOutputType(String componentType) {
		
		return components_tags_classified.get(type_output).contains(
		    componentType);
	}
	
	private boolean isSimpleType(String componentType) {
		
		return components_tags_classified.get(type_simple).contains(
		    componentType);
	}
	
	public boolean isInputComponent(FormComponent formComponent) {
		
		String type = formComponent.getType();
		return isSelectType(type) || isSimpleType(type);
	}
	
	public void filterNonDisplayComponents(List<String> all_components_types) {
		
		List<String> non_disp_types = components_tags_classified
		        .get(type_non_display);
		
		for (Iterator<String> iter = all_components_types.iterator(); iter
		        .hasNext();) {
			
			if (non_disp_types.contains(iter.next()))
				iter.remove();
		}
	}
	
	FormManager getFormManager() {
		return formManager;
	}
	
	public void setFormManager(FormManager formManager) {
		this.formManager = formManager;
	}
} public class FormDocumentImpl extends FormComponentContainerImpl implements
        com.idega.xformsmanager.business.Document,
        com.idega.xformsmanager.component.FormDocument {
	
	private FormVariablesHandler formVariablesHandler;
	private LocalizedStringBean formTitle;
	private LocalizedStringBean formErrorMsg;
	private Long formId;
	private Integer formVersion;
	private PropertiesDocument properties;
	private List<String> registeredForLastPageIdPages;
	private ParametersManager parametersManager;
	private String formType;
	private Map<Locale, Document> localizedComponentsDocuments;
	private Locale defaultLocale;
	private boolean formDocumentModified = true;
	private DocumentBuilder builder;
	
	private DMContext context;
	private Document xformsDocument;
	
	private PersistedFormDocument persistedFormForLazyLoading;
	private boolean loaded = false;
	
	private int lastComponentId = 0;
	
	public void setContainerElement(Element container_element) {
		getXFormsManager().setComponentsContainer(this, container_element);
	}
	
	@Override
	public XFormsManagerDocument getXFormsManager() {
		
		return getContext().getXformsManagerFactory()
		        .getXformsManagerDocument();
	}
	
	public Document getXformsDocument() {
		return xformsDocument;
	}
	
	public void populateSubmissionDataWithXML(Document submission, boolean clean) {
		
		getXFormsManager().populateSubmissionDataWithXML(this, submission,
		    clean);
	}
	
	public void setFormDocumentModified(boolean formDocumentModified) {
		this.formDocumentModified = formDocumentModified;
		
		if (formDocumentModified)
			getLocalizedComponentsDocuments().clear();
	}
	
	public boolean isFormDocumentModified() {
		return formDocumentModified;
	}
	
	public Document getComponentsXml(Locale locale) {
		
		Map<Locale, Document> localizedComponentsDocuments = getLocalizedComponentsDocuments();
		
		Document doc;
		
		if (!localizedComponentsDocuments.containsKey(locale)) {
			
			try {
				ComponentsGenerator componentsGenerator = getContext()
				        .getComponentsGenerator();
				Document xformClone = (Document) getXformsDocument().cloneNode(
				    true);
				
				FormManagerUtil.modifyXFormsDocumentForViewing(xformClone);
				FormManagerUtil.setCurrentFormLocale(xformClone, locale);
				FormManagerUtil
				        .modifyFormForLocalisationInFormbuilder(xformClone);
				
				doc = componentsGenerator
				        .generateHtmlRepresentation(xformClone);
				
				localizedComponentsDocuments.put(locale, doc);
				setFormDocumentModified(false);
				
			} catch (Exception e) {
				
				Logger.getLogger(getClass().getName()).log(Level.SEVERE,
				    "Exception while generating components html document", e);
				doc = localizedComponentsDocuments.isEmpty() ? null
				        : localizedComponentsDocuments.values().iterator()
				                .next();
			}
			
		} else {
			doc = localizedComponentsDocuments.get(locale);
		}
		
		return doc;
	}
	
	public Long getFormId() {
		
		return formId;
	}
	
	public void setFormId(Long formId) {
		
		FormManagerUtil.setFormId(getXformsDocument(), String.valueOf(formId));
		this.formId = formId;
	}
	
	@Override
	public String getId() {
		return String.valueOf(getFormId());
	}
	
	public Locale getDefaultLocale() {
		
		if (defaultLocale == null) {
			defaultLocale = FormManagerUtil
			        .getDefaultFormLocale(getXformsDocument());
		}
		
		return defaultLocale;
	}
	
	public void setDefaultLocale(Locale defaultLocale) {
		
		FormManagerUtil
		        .setDefaultFormLocale(getXformsDocument(), defaultLocale);
		this.defaultLocale = defaultLocale;
	}
	
	public Page addPage(String nextSiblingPageId) {
		
		if (nextSiblingPageId == null && !getContainedPagesIdList().isEmpty()) {
			
			// find the first special page to insert before
			
			for (String pageId : getContainedPagesIdList()) {
				
				if (((FormComponentPage) getContainedComponent(pageId))
				        .isSpecialPage()) {
					
					nextSiblingPageId = pageId;
					break;
				}
			}
		}
		
		Page page = (Page) super.addComponent(FormComponentFactory.page_type,
		    nextSiblingPageId);
		componentsOrderChanged();
		return page;
	}
	
	@Override
	public Component addComponent(String component_type,
	        String component_after_this_id) throws NullPointerException {
		throw new NullPointerException("Use addPage method instead");
	}
	
	public Page getPage(String pageId) {
		return (Page) getContainedComponent(pageId);
	}
	
	public List<Page> getSpecialPages() {
		
		ArrayList<Page> specialPages = new ArrayList<Page>(
		        getContainedComponentsIds().size());
		
		for (FormComponent childPage : getContainedComponents().values()) {
			
			if (((FormComponentPage) childPage).isSpecialPage()) {
				specialPages.add((Page) childPage);
			}
		}
		
		return specialPages;
	}
	
	public List<String> getContainedPagesIdList() {
		return getContainedComponentsIds();
	}
	
	public String generateNewComponentId() {
		
		if (lastComponentId == 0) {
			
			Set<String> allIds = FormManagerUtil
			        .getAllComponentsIds(getXformsDocument());
			
			for (String id : allIds) {
				int idNr = FormManagerUtil.parseIdNumber(id);
				
				if (idNr > lastComponentId)
					lastComponentId = idNr;
			}
		}
		
		return FormManagerUtil.CTID + (++lastComponentId);
	}
	
	public String getFormSourceCode() throws Exception {
		
		return FormManagerUtil.serializeDocument(getXformsDocument());
	}
	
	public void setFormSourceCode(String newSourceCode) throws Exception {
		
		if (builder == null)
			builder = XmlUtil.getDocumentBuilder();
		
		clear();
		
		ByteArrayInputStream bais = new ByteArrayInputStream(newSourceCode
		        .getBytes("UTF-8"));
		Document newXForm = builder.parse(new InputSource(bais));
		setXformsDocument(newXForm);
		loadDocument();
	}
	
	public void loadDocument() {
		
		loadDocumentInternal(null);
	}
	
	public void loadDocument(PersistedFormDocument persistedForm) {
		
		loadDocumentInternal(persistedForm);
	}
	
	public void lazyLoadDocument(PersistedFormDocument persistedForm) {
		
		if (persistedForm != null) {
			setFormId(persistedForm.getFormId());
			setFormType(persistedForm.getFormType());
			setFormVersion(persistedForm.getVersion());
		}
		
		setContainerElement(FormManagerUtil
		        .getComponentsContainerElement(getXformsDocument()));
		
		persistedFormForLazyLoading = persistedForm;
	}
	
	public void lazyLoadDocument() {
		lazyLoadDocument(null);
	}
	
	/**
	 * checks if document is loaded. If loadIfNotLoaded is true, then it loads the document if it
	 * isn't already
	 * 
	 * @param loadIfNotLoaded
	 */
	protected boolean isLazyLoaded(boolean loadIfNotLoaded) {
		
		if (!loaded && loadIfNotLoaded) {
			loadDocumentInternal(persistedFormForLazyLoading);
			loaded = true;
		}
		
		return loaded;
	}
	
	private void loadDocumentInternal(PersistedFormDocument persistedForm) {
		
		Document xformsXmlDoc = getXformsDocument();
		
		if (persistedForm != null) {
			setFormId(persistedForm.getFormId());
			setFormType(persistedForm.getFormType());
			setFormVersion(persistedForm.getVersion());
		}
		
		setContainerElement(FormManagerUtil
		        .getComponentsContainerElement(xformsXmlDoc));
		loadContainerComponents();
		setProperties();
		
		loaded = true;
	}
	
	public LocalizedStringBean getFormTitle() {
		
		if (formTitle == null)
			formTitle = FormManagerUtil.getFormTitle(getXformsDocument());
		
		return formTitle;
	}
	
	public LocalizedStringBean getFormErrorMsg() {
		
		if (formErrorMsg == null)
			formErrorMsg = FormManagerUtil.getFormErrorMsg(getXformsDocument());
		
		return formErrorMsg;
	}
	
	public void setFormTitle(LocalizedStringBean formTitle) {
		
		if (formTitle != null) {
			
			FormManagerUtil.setFormTitle(getXformsDocument(), formTitle);
			this.formTitle = formTitle;
		} else {
			Logger.getLogger(getClass().getName()).log(Level.WARNING,
			    "Tried to set form title, but no formTitle provided");
		}
	}
	
	public void setFormErrorMsg(LocalizedStringBean formError) {
		
		if (formError != null) {
			
			FormManagerUtil.setFormErrorMsg(getXformsDocument(), formError);
			this.formErrorMsg = formError;
		} else {
			Logger.getLogger(getClass().getName()).log(Level.WARNING,
			    "Tried to set form error message, but no formError provided");
		}
	}
	
	public void rearrangeDocument() {
		rearrangeComponents();
	}
	
	@Override
	public void remove() {
		throw new NullPointerException("You shall not remove ME!!!!");
	}
	
	@Override
	public void componentsOrderChanged() {
		
		Map<String, FormComponent> contained_components = getContainedComponents();
		int components_amount = getContainedComponents().size();
		int i = 0;
		
		for (String comp_id : getContainedComponentsIds()) {
			
			FormComponentPage page = (FormComponentPage) contained_components
			        .get(comp_id);
			if (page == null)
				throw new NullPointerException(
				        "Component, which id was provided in list was not found. Provided: "
				                + getId());
			
			page.setPageSiblings(i == 0 ? null
			        : (FormComponentPage) contained_components
			                .get(getContainedComponentsIds().get(i - 1)),
			    (i + 1) == components_amount ? null
			            : (FormComponentPage) contained_components
			                    .get(getContainedComponentsIds().get(i + 1)));
			
			page.pagesSiblingsChanged();
			i++;
		}
		announceRegisteredForLastPage();
	}
	
	protected void announceRegisteredForLastPage() {
		
		for (FormComponent childPage : getContainedComponents().values()) {
			
			if (FormComponentFactory.page_type_thx.equals(childPage.getType())) {
				
				dispatchEvent(Event.thxPageIdChanged, childPage.getId(), this);
				break;
			}
		}
	}
	
	@Override
	public void rearrangeComponents() {
		
		List<String> contained_components_id_list = getContainedComponentsIds();
		int components_amount = contained_components_id_list.size();
		Map<String, FormComponent> contained_components = getContainedComponents();
		
		for (int i = components_amount - 1; i >= 0; i--) {
			
			String component_id = contained_components_id_list.get(i);
			
			if (contained_components.containsKey(component_id)) {
				
				FormComponentPage page = (FormComponentPage) contained_components
				        .get(component_id);
				
				if (i != components_amount - 1) {
					
					page.setNextSiblingRerender(contained_components
					        .get(contained_components_id_list.get(i + 1)));
				} else
					page.setNextSiblingRerender(null);
				
				page
				        .setPageSiblings(i == 0 ? null
				                : (FormComponentPage) contained_components
				                        .get(getContainedComponentsIds().get(
				                            i - 1)),
				            (i + 1) == components_amount ? null
				                    : (FormComponentPage) contained_components
				                            .get(getContainedComponentsIds()
				                                    .get(i + 1)));
				page.pagesSiblingsChanged();
				
			} else
				throw new NullPointerException(
				        "Component, which id was provided in list was not found. Provided: "
				                + component_id);
		}
	}
	
	@Override
	public void loadContainerComponents() {
		super.loadContainerComponents();
		componentsOrderChanged();
	}
	
	@Override
	public void setProperties() {
		
		ComponentPropertiesDocument properties = (ComponentPropertiesDocument) getProperties();
		
		if (properties == null)
			return;
		
		properties.setPlainStepsVisualizationUsed(getXFormsManager()
		        .getIsStepsVisualizationUsed(this));
		properties.setPlainSubmissionAction(getXFormsManager()
		        .getSubmissionAction(this));
	}
	
	public void save() throws Exception {
		
		PersistenceManager persistenceManager = getContext()
		        .getPersistenceManager();
		
		if (persistenceManager == null)
			throw new NullPointerException("Persistence manager not set");
		
		PersistedFormDocument formDocument = persistenceManager.saveForm(this);
		setFormType(formDocument.getFormType());
		setFormId(formDocument.getFormId());
	}
	
	public void saveAllVersions(Long parentId) throws Exception {
		
		PersistenceManager persistenceManager = getContext()
		        .getPersistenceManager();
		
		if (persistenceManager == null)
			throw new NullPointerException("Persistence manager not set");
		
		PersistedFormDocument formDocument = persistenceManager
		        .saveAllVersions(this, parentId);
		setFormType(formDocument.getFormType());
		setFormId(formDocument.getFormId());
	}
	
	public void save(String storeBasePath) throws Exception {
		
		PersistenceManager persistenceManager = getContext()
		        .getPersistenceManager();
		
		if (persistenceManager == null)
			throw new NullPointerException("Persistence manager not set");
		
		PersistedFormDocument formDocument = persistenceManager.saveForm(this,
		    storeBasePath);
		setFormType(formDocument.getFormType());
		setFormId(formDocument.getFormId());
	}
	
	public Page getConfirmationPage() {
		
		return (Page) getFormConfirmationPage();
	}
	
	public FormComponentPage getFormConfirmationPage() {
		
		for (FormComponent childPage : getContainedComponents().values()) {
			
			if (FormComponentFactory.confirmation_page_type.equals(childPage
			        .getType())) {
				return (FormComponentPage) childPage;
			}
		}
		
		return null;
	}
	
	protected List<String> getRegisteredForLastPageIdPages() {
		
		if (registeredForLastPageIdPages == null)
			registeredForLastPageIdPages = new ArrayList<String>();
		
		return registeredForLastPageIdPages;
	}
	
	public void registerForLastPage(String register_page_id) {
		
		if (!getContainedComponents().containsKey(register_page_id))
			throw new IllegalArgumentException(
			        "I don't contain provided page id: " + register_page_id);
		
		if (!getRegisteredForLastPageIdPages().contains(register_page_id))
			getRegisteredForLastPageIdPages().add(register_page_id);
	}
	
	public Page addConfirmationPage() {
		
		if (getConfirmationPage() != null)
			throw new IllegalArgumentException(
			        "Confirmation page already exists in the form");
		
		Page page = (Page) super.addComponent(
		    FormComponentFactory.confirmation_page_type, null);
		
		componentsOrderChanged();
		addToConfirmationPage();
		
		return page;
	}
	
	public Element getAutofillModelElement() {
		
		return getXFormsManager().getAutofillAction(this);
	}
	
	public Element getFormDataModelElement() {
		
		return getXFormsManager().getFormDataModelElement(this);
	}
	
	public Element getFormMainDataInstanceElement() {
		
		return getXFormsManager().getFormMainDataInstanceElement(this);
	}
	
	public void clear() {
		
		setXformsDocument(null);
		lastComponentId = 0;
		setFormDocumentModified(true);
		
		getLocalizedComponentsDocuments().clear();
		setRegisteredForLastPageIdPages(null);
		formTitle = null;
		parametersManager = null;
		getContainedComponentsIds().clear();
		getContainedComponents().clear();
		formVariablesHandler = null;
	}
	
	@Override
	public void unregisterComponent(String component_id) {
		
		super.unregisterComponent(component_id);
		getRegisteredForLastPageIdPages().remove(component_id);
	}
	
	@Override
	public PropertiesDocument getProperties() {
		
		if (properties == null) {
			ComponentPropertiesDocument properties = new ComponentPropertiesDocument();
			properties.setComponent(this);
			this.properties = properties;
		}
		
		return properties;
	}
	
	public Element getSectionsVisualizationInstanceElement() {
		
		return getXFormsManager().getSectionsVisualizationInstanceElement(this);
	}
	
	@Override
	public void update(ConstUpdateType what) {
		
		getXFormsManager().update(this, what, null);
		
		switch (what) {
			
			case STEPS_VISUALIZATION_USED:

				rearrangeComponents();
				break;
			
			case SUBMISSION_ACTION:

				break;
			
			default:
				break;
		}
	}
	
	public void setRegisteredForLastPageIdPages(
	        List<String> registeredForLastPageIdPages) {
		this.registeredForLastPageIdPages = registeredForLastPageIdPages;
	}
	
	public ParametersManager getParametersManager() {
		
		if (parametersManager == null) {
			parametersManager = new ParametersManager();
			parametersManager.setFormDocumentComponent(this);
		}
		
		return parametersManager;
	}
	
	public Element getSubmissionElement() {
		// TODO: this can be put to component data bean and lazy loaded there
		return FormManagerUtil.getSubmissionElement(getXformsDocument());
	}
	
	public Element getSubmissionInstanceElement() {
		// TODO: this can be put to component data bean and lazy loaded there
		return FormManagerUtil
		        .getFormSubmissionInstanceElement(getXformsDocument());
	}
	
	public FormVariablesHandler getFormVariablesHandler() {
		
		if (formVariablesHandler == null)
			formVariablesHandler = new FormVariablesHandler(getXformsDocument());
		
		return formVariablesHandler;
	}
	
	public String getFormType() {
		return formType;
	}
	
	public void setFormType(String formType) {
		this.formType = formType;
	}
	
	public Integer getFormVersion() {
		return formVersion;
	}
	
	public void setFormVersion(Integer formVersion) {
		this.formVersion = formVersion;
	}
	
	public Map<Locale, Document> getLocalizedComponentsDocuments() {
		
		if (localizedComponentsDocuments == null)
			localizedComponentsDocuments = new HashMap<Locale, Document>(4);
		
		return localizedComponentsDocuments;
	}
	
	public boolean isReadonly() {
		return getXFormsManager().isReadonly(this);
	}
	
	public void setReadonly(boolean readonly) {
		
		getXFormsManager().setReadonly(this, readonly);
	}
	
	public void setPdfForm(boolean generatePdf) {
		
		getXFormsManager().setPdfForm(this, generatePdf);
	}
	
	public boolean isPdfForm() {
		
		return getXFormsManager().isPdfForm(this);
	}
	
	public DMContext getContext() {
		return context;
	}
	
	public void setContext(DMContext context) {
		this.context = context;
	}
	
	public Document getComponentsXforms() {
		return getContext().getCacheManager().getComponentsTemplate();
	}
	
	@Override
	public FormDocument getFormDocument() {
		return this;
	}
	
	@Override
	public void setFormDocument(FormDocument formDocument) {
		throw new UnsupportedOperationException(
		        "setting form document for formdocument not supported");
	}
	
	public void setXformsDocument(Document xformsDocument) {
		this.xformsDocument = xformsDocument;
	}
	
	public Element createXFormsElement(String tagExpression) {
		
		Element model = getFormDataModelElement();
		return model.getOwnerDocument().createElementNS(
		    model.getNamespaceURI(), tagExpression);
	}
	
	public Element createIdegaXFormsElement(String tagExpression) {
		
		Element model = getFormDataModelElement();
		return model.getOwnerDocument().createElementNS(
		    FormManagerUtil.idega_namespace, tagExpression);
	}
	
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder(super.toString());
		sb.append("getFormType(): ").append(getFormType()).append(CoreConstants.NEWLINE)
		.append("getId(): ").append(getId()).append(CoreConstants.NEWLINE)
		.append("getType(): ").append(getType()).append(CoreConstants.NEWLINE)
		.append("getDefaultLocale(): ").append(getDefaultLocale()).append(CoreConstants.NEWLINE)
		.append("getFormId(): ").append(getFormId()).append(CoreConstants.NEWLINE)
		.append("getFormTitle(): ").append(getFormTitle()).append(CoreConstants.NEWLINE)
		.append("getFormVersion(): ").append(getFormVersion()).append(CoreConstants.NEWLINE);
		
		try {
			sb.append("getFormSourceCode(): ").append(getFormSourceCode()).append(CoreConstants.NEWLINE);
		} catch (Exception e) {
			java.util.logging.Logger.getLogger(getClass().getName())
					.log(Level.WARNING, "Unable to append: getFormSourceCode() for " + 
							FormDocumentImpl.class.getName(), e);
		}		
		
		return sb.toString();
	}
} public class FormDocumentTemplateImpl implements FormDocument {
	
	private Document xformsDocument;
	private DMContext context;
	
	public Document getXformsDocument() {
		return xformsDocument;
	}
	
	public void setXformsDocument(Document xformsDocument) {
		this.xformsDocument = xformsDocument;
	}
	
	public DMContext getContext() {
		return context;
	}
	
	public void setContext(DMContext context) {
		this.context = context;
	}
	
	public String getId() {
		return "Form Components Template";
	}
	
	public String generateNewComponentId() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
	}
	
	public Element getAutofillModelElement() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public Document getComponentsXml(Locale locale) {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
	}
	
	public Locale getDefaultLocale() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public FormComponentPage getFormConfirmationPage() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public Element getFormDataModelElement() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public Long getFormId() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public Element getFormMainDataInstanceElement() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public LocalizedStringBean getFormTitle() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public String getFormType() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public PropertiesDocument getProperties() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public Element getSectionsVisualizationInstanceElement() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public Element getSubmissionElement() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public boolean isFormDocumentModified() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
	}
	
	public void registerForLastPage(String register_page_id) {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public void setFormDocumentModified(boolean changed) {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public FormComponent addFormComponent(String componentType,
	        String nextSiblingId) {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public void componentsOrderChanged() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public FormComponent getContainedComponent(String componentId) {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public List<String> getContainedComponentsIds() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public FormComponentPage getParentPage() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public XFormsManagerContainer getXFormsManager() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public void unregisterComponent(String componentId) {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public void addToConfirmationPage() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public void create() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public FormDocument getFormDocument() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public FormComponent getNextSibling() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public FormComponentContainer getParent() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public String getType() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public ComponentDataBean getComponentDataBean() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public void load() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public void loadFromTemplate() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public void remove() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public void setFormDocument(FormDocument form_document) {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public void setId(String id) {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public void setNextSibling(FormComponent component) {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public void setNextSiblingRerender(FormComponent nextSibling) {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public void setParent(FormComponentContainer parent) {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public void setType(String type) {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public void setComponentDataBean(ComponentDataBean xformsComponentDataBean) {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public void update(ConstUpdateType what) {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
		
	}
	
	public void update(ConstUpdateType what, Object property) {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
	}
	
	public void dispatchEvent(Event event, Object eventContext,
	        FormComponent dispatcher) {
		
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
	}
	
	public Element createXFormsElement(String tagExpression) {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
	}
	
	public Node appendChildNode(Node childNode) {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
	}
	
	public void mappingSiblingChanged(String... relevantMappings) {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
	}
	
	public Element createIdegaXFormsElement(String tagExpression) {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
	}
	
	public boolean isInputComponent() {
		throw new UnsupportedOperationException(
		        "Unsupported for template document");
	}

	public FormComponentMapping getFormComponentMapping(Nodeset nodeset) {
		throw new UnsupportedOperationException(
        "Unsupported for template document");
    }
} public class DMContext {
	
	private CacheManager cacheManager;
	private PersistenceManager persistenceManager;
	private XFormsManagerFactory xformsManagerFactory;
	private HtmlManagerFactory htmlManagerFactory;
	private FormComponentFactory formComponentFactory;
	private ComponentsGenerator componentsGenerator;
	private ComponentsTemplateImpl componentsTemplate;
	
	public XFormsManagerFactory getXformsManagerFactory() {
		return xformsManagerFactory;
	}
	
	public void setXformsManagerFactory(
	        XFormsManagerFactory xformsManagerFactory) {
		this.xformsManagerFactory = xformsManagerFactory;
	}
	
	public CacheManager getCacheManager() {
		return cacheManager;
	}
	
	public void setCacheManager(CacheManager cacheManager) {
		this.cacheManager = cacheManager;
	}
	
	public PersistenceManager getPersistenceManager() {
		return persistenceManager;
	}
	
	public void setPersistenceManager(PersistenceManager persistenceManager) {
		this.persistenceManager = persistenceManager;
	}
	
	public HtmlManagerFactory getHtmlManagerFactory() {
		return htmlManagerFactory;
	}
	
	public void setHtmlManagerFactory(HtmlManagerFactory htmlManagerFactory) {
		this.htmlManagerFactory = htmlManagerFactory;
	}
	
	public Document getComponentsTemplateDocument() {
		return getCacheManager().getComponentsTemplate();
	}
	
	public FormComponentFactory getFormComponentFactory() {
		return formComponentFactory;
	}
	
	public void setFormComponentFactory(
	        FormComponentFactory formComponentFactory) {
		this.formComponentFactory = formComponentFactory;
	}
	
	public ComponentsGenerator getComponentsGenerator() {
		return componentsGenerator;
	}
	
	public void setComponentsGenerator(ComponentsGenerator componentsGenerator) {
		this.componentsGenerator = componentsGenerator;
	}
	
	public ComponentsTemplateImpl getComponentsTemplate() {
		return componentsTemplate;
	}
	
	public void setComponentsTemplate(ComponentsTemplateImpl componentsTemplate) {
		this.componentsTemplate = componentsTemplate;
	}
} public interface ComponentsGenerator {

	/**
	 * 
	 * @return <code>true</code> when init() method already called, 
	 * <code>false</code> otherwise;
	 * @author <a href="mailto:martynas@idega.com">Martynas Stakė</a>
	 */
	public boolean isInstantiated();
	
	public abstract void init(IWMainApplication iwma,
			TransformerService transfService);

	public abstract Document generateHtmlRepresentation(Document xform);
} @Service("htmlFact")
@Scope("singleton")
public class HtmlManagerFactory {

	@Autowired private HtmlManager 		htmlManager;
	
	public HtmlManager getHtmlManager() {
		return htmlManager;
	}
	public void setHtmlManager(HtmlManager htmlManager) {
		this.htmlManager = htmlManager;
	}
} @Service
@Scope("singleton")
public class XFormsManagerFactory {

	@Autowired
	@FormComponentType(FormComponentType.base)
	private XFormsManager xformsManager;
	@Autowired
	@FormComponentType(FormComponentType.button)
	private XFormsManagerButton xformsManagerButton;
	@Autowired
	@FormComponentType(FormComponentType.container)
	private XFormsManagerContainer xformsManagerContainer;
	@Autowired
	@FormComponentType(FormComponentType.document)
	private XFormsManagerDocument xformsManagerDocument;
	@Autowired
	@FormComponentType(FormComponentType.page)
	private XFormsManagerPage xformsManagerPage;
	@Autowired
	@FormComponentType(FormComponentType.plain)
	private XFormsManagerPlain xformsManagerPlain;
	@Autowired
	@FormComponentType(FormComponentType.select)
	private XFormsManagerSelect xformsManagerSelect;
	@Autowired
	@FormComponentType(FormComponentType.multiupload)
	private XFormsManagerMultiUpload xformsManagerMultiUploadDescription;

	public XFormsManagerFactory() {
	}

	public XFormsManager getXformsManager() {
		return xformsManager;
	}

	public void setXformsManager(XFormsManager xformsManager) {
		this.xformsManager = xformsManager;
	}

	public XFormsManagerButton getXformsManagerButton() {
		return xformsManagerButton;
	}

	public void setXformsManagerButton(XFormsManagerButton xformsManagerButton) {
		this.xformsManagerButton = xformsManagerButton;
	}

	public XFormsManagerContainer getXformsManagerContainer() {
		return xformsManagerContainer;
	}

	public void setXformsManagerContainer(
			XFormsManagerContainer xformsManagerContainer) {
		this.xformsManagerContainer = xformsManagerContainer;
	}

	public XFormsManagerDocument getXformsManagerDocument() {
		return xformsManagerDocument;
	}

	public void setXformsManagerDocument(
			XFormsManagerDocument xformsManagerDocument) {
		this.xformsManagerDocument = xformsManagerDocument;
	}

	public XFormsManagerPage getXformsManagerPage() {
		return xformsManagerPage;
	}

	public void setXformsManagerPage(XFormsManagerPage xformsManagerPage) {
		this.xformsManagerPage = xformsManagerPage;
	}

	public XFormsManagerPlain getXformsManagerPlain() {
		return xformsManagerPlain;
	}

	public void setXformsManagerPlain(XFormsManagerPlain xformsManagerPlain) {
		this.xformsManagerPlain = xformsManagerPlain;
	}

	public XFormsManagerSelect getXformsManagerSelect() {
		return xformsManagerSelect;
	}

	public void setXformsManagerSelect(XFormsManagerSelect xformsManagerSelect) {
		this.xformsManagerSelect = xformsManagerSelect;
	}

	public XFormsManagerMultiUpload getXformsManagerMultiUploadDescription() {
		return xformsManagerMultiUploadDescription;
	}

	public void setXformsManagerMultiUploadDescription(
			XFormsManagerMultiUpload xformsManagerMultiUploadDescription) {
		this.xformsManagerMultiUploadDescription = xformsManagerMultiUploadDescription;
	}
} public class FormManagerUtil {

	public static final String model_tag = "xf:model";
	public static final String label_tag = "xf:label";
	public static final String alert_tag = "xf:alert";
	public static final String help_tag = "xf:help";
	public static final String head_tag = "head";
	public static final String id_att = "id";
	public static final String at_att = "at";
	public static final String type_att = "type";
	public static final String constraint_att = "constraint";
	public static final String slash = "/";
	public static final String fb_ = "fb_";
	public static final String loc_ref_part1 = "instance('localized_strings')/";
	public static final String loc_ref_part2 = "[@lang=instance('localized_strings')/current_language]";
	public static final String inst_start = "instance('";
	public static final String inst_end = "')";
	public static final String data_mod = "data_model";
	public static final String loc_tag = "localized_strings";
	public static final String output_tag = "idega:output";
	public static final String ref_s_att = "ref";
	public static final String lang_att = "lang";
	public static final String CTID = XFormsUtil.CTID;
	public static final String localized_entries = "localizedEntries";
	public static final String body_tag = "body";
	public static final String bind_att = "bind";
	public static final String bind_tag = "xf:bind";
	public static final String name_att = "name";
	public static final String schema_tag = "xs:schema";
	public static final String form_id = "form_id";
	public static final String title_tag = "title";
	public static final String nodeset_att = "nodeset";
	public static final String group_tag = "xf:group";
	// public static final String switch_tag = "xf:switch";
	// public static final String case_tag = "xf:case";
	public static final String idegans_switch_tag = "idega:switch";
	public static final String idegans_case_tag = "idega:case";
	public static final String submit_tag = "xf:submit";
	public static final String itemset_tag = "xf:itemset";
	public static final String item_tag = "xf:item";
	public static final String model_att = "model";
	public static final String src_att = "src";
	public static final String context_att_pref = "context:";
	public static final String item_label_tag = "itemLabel";
	public static final String item_value_tag = "itemValue";
	public static final String localized_entries_tag = "localizedEntries";
	public static final String default_language_tag = "default_language";
	public static final String current_language_tag = "current_language";
	public static final String form_id_tag = "form_id";
	public static final String submission_tag = "xf:submission";
	public static final String page_tag = "page";
	public static final String toggle_tag = "idega:toggle";
	public static final String number_att = "number";
	public static final String case_att = "case";
	public static final String p3ptype_att = "p3ptype";
	public static final String instance_tag = "xf:instance";
	public static final String setvalue_tag = "xf:setvalue";
	public static final String setvalue_tag_idega_ns = "idega:setvalue";
	public static final String div_tag = "div";
	public static final String trigger_tag = "xf:trigger";
	public static final String preview = "preview";
	public static final String component_tag = "component";
	public static final String component_id_att = "component_id";
	public static final String autofill_model_id = "x-autofill-model";
	public static final String xmlns_att = "xmlns";
	public static final String relevant_att = "relevant";
	public static final String shared_att = "shared";
	public static final String autofill_instance_ending = "_autofill-instance";
	public static final String autofill_setvalue_ending = "-autofill-setvalue";
	public static final String value_att = "value";
	public static final String autofill_key_prefix = KeyContextResolver.autofill_key_prefix;
	public static final String refresh_tag = "xf:refresh";
	public static final String sections_visualization_id = "sections_visualization";
	public static final String sections_visualization_instance_id = "sections_visualization_instance";
	public static final String section_item = "section_item";
	public static final String sections_visualization_instance_item = "sections_visualization_instance_item";
	public static final String sections_visualization_item = "sections_visualization_item";
	public static final String set_section_vis_cur = "_set_section_vis_cur";
	public static final String set_section_vis_rel = "_set_section_vis_rel";
	public static final String event_att = "ev:event";
	public static final String DOMActivate_att_val = "DOMActivate";
	public static final String xforms_namespace_uri = "http://www.w3.org/2002/xforms";
	public static final String event_namespace_uri = "http://www.w3.org/2001/xml-events";
	public static final String idega_namespace = "http://idega.com/xforms";
	public static final String mapping_att = ChibaConstants.MAPPING;
	public static final String action_att = "action";
	public static final String required_att = "required";
	public static final String readonly_att = "readonly";
	public static final String xpath_true = "true()";
	public static final String true_string = "true";
	public static final String false_string = "false";
	public static final String xpath_false = "false()";
	public static final String datatype_tag = "datatype";
	public static final String accessSupport_att = "accessSupport";
	public static final String submission_model = "submission_model";
	public static final String nodeTypeAtt = "nodeType";
	public static final String controlInstanceID = "control-instance";
	public static final String calculate_att = "calculate";
	private static final String simple_type = "xs:simpleType";
	private static final String complex_type = "xs:complexType";

	private static final String line_sep = "line.separator";
	private static final String xml_mediatype = "text/html";
	private static final String utf_8_encoding = "UTF-8";

	private static OutputFormat output_format;
	private static Pattern non_xml_pattern = Pattern
	        .compile("[a-zA-Z0-9{-}{_}]");

	private static final XPathUtil formInstanceModelElementXPath = new XPathUtil(
	        ".//xf:model[xf:instance/@id='data-instance']");
	private static final XPathUtil defaultFormModelElementXPath = new XPathUtil(
	        ".//xf:model");
	private static final XPathUtil formModelElementXPath = new XPathUtil(
	        ".//xf:model[@id=$modelId]");
	private static final XPathUtil formSubmissionInstanceElementXPath = new XPathUtil(
	        ".//xf:instance[@id='data-instance']");
	private static final XPathUtil instanceElementXPath = new XPathUtil(
	        ".//xf:instance");
	private static final XPathUtil submissionElementXPath = new XPathUtil(
	        ".//xf:submission[@id='submit_data_submission']");

	private static final XPathUtil formTitleOutputElementXPath = new XPathUtil(".//h:title//xf:output");

	private static final XPathUtil instanceElementByIdXPath = new XPathUtil(
	        ".//xf:instance[@id=$instanceId]");
	private static final XPathUtil formSubmissionInstanceDataElementXPath = new XPathUtil(
	        ".//xf:instance[@id='data-instance']/data");
	private static final XPathUtil localizedStringElementXPath = new XPathUtil(
	        ".//xf:instance[@id='localized_strings']/localized_strings");
	private static final XPathUtil elementByIdXPath = new XPathUtil(
	        ".//*[@id=$id]");
	// private static final XPathUtil elementsContainingAttributeXPath = new XPathUtil(
	// ".//*[($elementName = '*' or name(.) = $elementName) and ($attributeName = '*' or attribute::*[name(.) = $attributeName])]");
	private static final XPathUtil replaceAttributesByExpressionXPath = new XPathUtil(
	        ".//attribute::*[contains(., $expression)]");
	private static final XPathUtil localizaionSetValueElement = new XPathUtil(
	        ".//xf:setvalue[@model='data_model']");
	private static final XPathUtil formErrorMessageXPath = new XPathUtil(
	        ".//xf:action[@id='idega-submission-error']/xf:message");
	private static final XPathUtil formParamsXPath = new XPathUtil(
	        ".//*[@nodeType='formParams']");
	private static final XPathUtil labelElementXPath = new XPathUtil(
	        ".//xf:label");
	private static final XPathUtil bindsByNodesetXPath = new XPathUtil(
	        ".//xf:bind[@nodeset=$nodeset]");
	private static final String nodesetVariable = "nodeset";

	private final static String expressionVariable = "expression";
	private final static String elementNameVariable = "elementName";
	private final static String attributeNameVariable = "attributeName";

	public static final class XFormEvent implements XFormsEventNames {

		public static final String XFORMS_VALUE_CHANGED = VALUE_CHANGED;
	}

	private FormManagerUtil() {
	}

	public static void insertNodesetElement(Document form_xforms,
	        Element new_nodeset_element) {

		Element container = (Element) ((Element) form_xforms
		        .getElementsByTagName(instance_tag).item(0))
		        .getElementsByTagName("data").item(0);
		container.appendChild(new_nodeset_element);
	}

	/**
	 * Puts localized text on element. Localization is saved on the xforms document.
	 *
	 * @param key
	 *            - new localization message key
	 * @param oldKey
	 *            - old key, if provided, is used for replacing with new_key
	 * @param element
	 *            - element, to change or put localization message
	 * @param xform
	 *            - xforms document
	 * @param localizedStr
	 *            - localized message
	 * @throws NullPointerException
	 *             - something necessary not provided
	 */
	public static void putLocalizedText(String attributeName, String key,
	        String oldKey, Element element, Document xform,
	        LocalizedStringBean localizedStr) throws NullPointerException {

		String ref = element.getAttribute(attributeName);

		if (StringUtil.isEmpty(ref) && StringUtil.isEmpty(key))
			throw new NullPointerException(
			        "Localization to element not initialized and key for new localization string not presented.");

		if (key != null) {
			// creating new key

			ref = new StringBuffer(loc_ref_part1).append(key)
			        .append(loc_ref_part2).toString();

			element.setAttribute(attributeName, ref);

		} else if (isLocalizableExpressionCorrect(ref)) {
			// get key from ref
			key = getKeyFromRef(ref);

		} else
			throw new NullPointerException(
			        "Ref and key not specified or ref has incorrect format. Ref: "
			                + ref);

		Element localizationStringsElement = FormManagerUtil
		        .getLocalizedStringElement(xform);

		if (oldKey != null) {

			NodeList oldLocalizationTags = localizationStringsElement
			        .getElementsByTagName(oldKey);

			// find and rename those elements
			for (int i = 0; i < oldLocalizationTags.getLength(); i++) {

				Element localizationTag = (Element) oldLocalizationTags.item(i);
				xform.renameNode(localizationTag,
				    localizationTag.getNamespaceURI(), key);
			}
		}

		NodeList localizationTags = localizationStringsElement
		        .getElementsByTagName(key);

		List<String> locales = new ArrayList<String>();

		for (Locale locale : localizedStr.getLanguagesKeySet())
			locales.add(locale.toString());

		// removing elements that correspond to locale, which we don't need (anymore)
		List<Node> nodesToRemove = new ArrayList<Node>();

		for (int i = 0; i < localizationTags.getLength(); i++) {

			Element localizationTag = (Element) localizationTags.item(i);

			if (!locales.contains(localizationTag.getAttribute(lang_att)))
				nodesToRemove.add(localizationTag);
		}

		for (Node node : nodesToRemove)
			node.getParentNode().removeChild(node);

		localizationTags = localizationStringsElement.getElementsByTagName(key);

		for (Locale locale : localizedStr.getLanguagesKeySet()) {

			boolean valueSet = false;

			if (localizationTags != null) {

				for (int i = 0; i < localizationTags.getLength(); i++) {

					Element localizationTag = (Element) localizationTags
					        .item(i);

					if (localizationTag.getAttribute(lang_att).equals(
					    locale.toString())) {

						if (localizedStr.getString(locale) != null)
							setElementsTextNodeValue(localizationTag,
							    localizedStr.getString(locale));

						valueSet = true;
						break;
					}
				}
			}

			if (localizationTags == null || !valueSet) {

				// create new localization element
				Element localizationElement = xform.createElement(key);
				localizationElement.setAttribute(lang_att, locale.toString());
				localizationElement.setTextContent(localizedStr
				        .getString(locale) == null ? CoreConstants.EMPTY
				        : localizedStr.getString(locale));
				localizationStringsElement.appendChild(localizationElement);
			}
		}
	}

	public static String getComponentLocalizationKey(String componentId,
	        String localizationKey) {

		if (!isLocalizationKeyCorrect(localizationKey))
			return null;

		String componentLocalizationKey = new StringBuilder(componentId)
		        .append(
		            localizationKey.contains(CoreConstants.MINUS) ? localizationKey
		                    .substring(localizationKey
		                            .indexOf(CoreConstants.MINUS))
		                    : CoreConstants.EMPTY).toString();

		return componentLocalizationKey;
	}

	public static String getKeyFromRef(String ref) {
		return ref.substring(ref.indexOf(slash) + 1, ref.indexOf("["));
	}

	public static boolean isLocalizableExpressionCorrect(String ref) {

		return ref != null && ref.length() != 0
		        && ref.startsWith(loc_ref_part1) && ref.endsWith(loc_ref_part2)
		        && !ref.contains(CoreConstants.SPACE);
	}

	public static LocalizedStringBean getLocalizedStrings(String key,
	        Document xformsDoc) {

		Element locModel = getElementById(xformsDoc, data_mod);
		Element locStrings = (Element) locModel.getElementsByTagName(loc_tag)
		        .item(0);

		NodeList keyElements = locStrings.getElementsByTagName(key);
		LocalizedStringBean locStrBean = new LocalizedStringBean();

		for (int i = 0; i < keyElements.getLength(); i++) {

			Element keyElement = (Element) keyElements.item(i);

			String langCode = keyElement.getAttribute(lang_att);

			if (langCode != null) {

				String content = getElementsTextNodeValue(keyElement);
				locStrBean.setString(LocaleUtil.getLocale(langCode),
				    content == null ? CoreConstants.EMPTY : content);
			}
		}

		return locStrBean;
	}

	public static LocalizedStringBean getLabelLocalizedStrings(
	        Element component, Document xforms_doc) {

		NodeList labels = component
		        .getElementsByTagName(FormManagerUtil.label_tag);

		if (labels == null || labels.getLength() == 0)
			return new LocalizedStringBean();

		Element label = (Element) labels.item(0);

		return getElementLocalizedStrings(label, xforms_doc);
	}

	public static LocalizedStringBean getElementLocalizedStrings(Element element, Document xforms_doc) {
		String ref = null;
		try {
			ref = element.getAttributeNS(idega_namespace, "ref");
		} catch (NullPointerException e) {
			Logger.getLogger(FormManagerUtil.class.getName()).log(Level.WARNING,
					"Element is null");
			com.idega.util.xml.XmlUtil.prettyPrintDOM(xforms_doc);
		}

		if (StringUtil.isEmpty(ref))
			ref = element.getAttribute(FormManagerUtil.ref_s_att);

		if (!isLocalizableExpressionCorrect(ref))
			return new LocalizedStringBean();

		String key = getKeyFromRef(ref);

		return getLocalizedStrings(key, xforms_doc);
	}

	public static void clearLocalizedMessagesFromDocument(Document doc) {

		Element loc_model = getElementById(doc, data_mod);
		Element loc_strings = (Element) loc_model.getElementsByTagName(loc_tag)
		        .item(0);
		@SuppressWarnings("unchecked")
		List<Element> loc_elements = DOMUtil.getChildElements(loc_strings);

		for (Iterator<Element> iter = loc_elements.iterator(); iter.hasNext();)
			FormManagerUtil.removeTextNodes(iter.next());
	}

	public static Locale getDefaultFormLocale(Document xformsDoc) {

		Element locModel = getElementById(xformsDoc, data_mod);
		Element locStrings = (Element) locModel.getElementsByTagName(loc_tag)
		        .item(0);
		NodeList defaultLanguages = locStrings
		        .getElementsByTagName(default_language_tag);

		String langCode = null;

		if (defaultLanguages != null && defaultLanguages.getLength() != 0) {
			langCode = getElementsTextNodeValue(defaultLanguages.item(0));
		}
		if (langCode == null)
			langCode = "en";

		return LocaleUtil.getLocale(langCode);
	}

	public static void setCurrentFormLocale(Document form_xforms, Locale locale) {
		Element loc_model = getElementById(form_xforms, data_mod);
		Element loc_strings = (Element) loc_model.getElementsByTagName(loc_tag)
		        .item(0);
		NodeList current_language_node_list = loc_strings
		        .getElementsByTagName(current_language_tag);

		if (current_language_node_list != null
		        && current_language_node_list.getLength() != 0) {
			// String localeStr = locale.toString().toLowerCase();
			String localeStr = locale.toString();
			setElementsTextNodeValue(current_language_node_list.item(0),
			    localeStr);
		}
	}

	public static void setDefaultFormLocale(Document xform, Locale locale) {

		Element loc_model = getElementById(xform, data_mod);
		Element loc_strings = (Element) loc_model.getElementsByTagName(loc_tag)
		        .item(0);
		NodeList current_language_node_list = loc_strings
		        .getElementsByTagName(default_language_tag);

		if (current_language_node_list != null
		        && current_language_node_list.getLength() != 0) {
			// String localeStr = locale.toString().toLowerCase();
			String localeStr = locale.toString();
			setElementsTextNodeValue(current_language_node_list.item(0),
			    localeStr);
		}
	}

	private static final XPathUtil validatorMessagesElementsXPath = new XPathUtil(
	        ".//idega:validator/idega:message", new Prefix("idega",
	                idega_namespace));

	private static final XPathUtil validatorBlockElementsXPath = new XPathUtil(
	        ".//idega:validator", new Prefix("idega", idega_namespace));

	public static Map<ErrorType, LocalizedStringBean> getErrorLabelLocalizedStrings(
	        Node context) {

		// <idega:validator ev:event="idega-validate">
		// <idega:message errorType="required" model="data_model"
		// value="instance('localized_strings')/email-required[@lang=instance('localized_strings')/current_language]"/>

		NodeList validatorMessagesElements = validatorMessagesElementsXPath
		        .getNodeset(context);
		HashMap<ErrorType, LocalizedStringBean> errors = new HashMap<ErrorType, LocalizedStringBean>(
		        validatorMessagesElements.getLength());

		for (int i = 0; i < validatorMessagesElements.getLength(); i++) {

			Element el = (Element) validatorMessagesElements.item(i);
			String errorTypeAtt = el.getAttribute("errorType");

			ErrorType errorType = ErrorType
			        .getByStringRepresentation(errorTypeAtt);
			String value = el.getAttribute(value_att);

			LocalizedStringBean err;

			if (value == null || value.length() == 0) {

				Logger.getLogger(FormManagerUtil.class.getName())
				        .log(Level.WARNING,
				            "Error message element present in document, but no value specified");
				err = new LocalizedStringBean();

			} else if (!isLocalizableExpressionCorrect(value)) {

				Logger.getLogger(FormManagerUtil.class.getName())
				        .log(
				            Level.WARNING,
				            "Error message element present in document, but no value expression incorrect. Provided="
				                    + value);
				err = new LocalizedStringBean();

			} else {

				String key = getKeyFromRef(value);
				err = getLocalizedStrings(key, context.getOwnerDocument());
			}

			errors.put(errorType, err);
		}

		return errors;
	}

	public static void setErrorLabelLocalizedStrings(Element componentElement,
	        String componentId, String componentKey, ErrorStringBean errString,
	        Document componentsTemplate) {

		NodeList validatorMessagesElements = validatorMessagesElementsXPath
		        .getNodeset(componentElement);

		if (validatorMessagesElements.getLength() != 0) {

			for (int i = 0; i < validatorMessagesElements.getLength(); i++) {

				Element el = (Element) validatorMessagesElements.item(i);
				String errorTypeAtt = el.getAttribute("errorType");

				ErrorType errorType = ErrorType
				        .getByStringRepresentation(errorTypeAtt);

				if (errString.getErrorType() == errorType) {

					putLocalizedText(value_att, null, null, el,
					    el.getOwnerDocument(),
					    errString.getLocalizedStringBean());
					return;
				}
			}
		} else {

			// assuming there are no validation block

			List<Element> validationBlockElements = FormManagerUtil
			        .getItemElementsById(componentsTemplate,
			            "validationMessagesHandling");

			for (Element element : validationBlockElements) {

				Element validationBlock = (Element) componentElement
				        .getOwnerDocument().importNode(element, true);
				validationBlock = (Element) componentElement
				        .appendChild(validationBlock);
			}

			replaceAttributesByExpression(componentElement, "componentId",
			    componentId);
		}

		// create message element

		Element validationBlock = validatorBlockElementsXPath
		        .getNode(componentElement);

		// <idega:message errorType="" model="data_model"
		// value="instance('localized_strings')/#{messageKey}[@lang=instance('localized_strings')/current_language]"/>

		Element messageElement = FormManagerUtil.getItemElementById(
		    componentsTemplate, "validationMessage");
		messageElement = (Element) validationBlock.getOwnerDocument()
		        .importNode(messageElement, true);
		messageElement = (Element) validationBlock.appendChild(messageElement);
		messageElement.setAttribute("errorType", errString.getErrorType()
		        .toString());

		String messageKey = componentKey + CoreConstants.MINUS
		        + errString.getErrorType();

		replaceAttributesByExpression(validationBlock, "messageKey", messageKey);
		putLocalizedText(value_att, null, null, messageElement,
		    messageElement.getOwnerDocument(),
		    errString.getLocalizedStringBean());
	}

	private static final XPathUtil helpOutputXPath = new XPathUtil(".//xf:help/xf:output");

	private static Element getHelpOutput(Element element) {
		Element help = helpOutputXPath.getNode(element);
		if (help == null)
			help = new XPathUtil(".//xf:help/idega:output").getNode(element);
		return help;
	}

	public static LocalizedStringBean getHelpTextLocalizedStrings(Element componentElement) {

		Element helpOutput = getHelpOutput(componentElement);

		LocalizedStringBean helpMsg;

		if (helpOutput == null) {

			helpMsg = new LocalizedStringBean();
		} else {

			String ref = helpOutput.getAttribute(ref_s_att);
			String key = getKeyFromRef(ref);

			helpMsg = getLocalizedStrings(key, helpOutput.getOwnerDocument());
		}

		return helpMsg;
	}

	public static void setHelpTextLocalizedStrings(Element componentElement,
	        String componentKey, LocalizedStringBean helpMsg,
	        Document componentsTemplate) {

		Element helpOutput = getHelpOutput(componentElement);

		if (helpOutput == null) {

			Element help = FormManagerUtil.getItemElementById(
			    componentsTemplate, "help");

			help = (Element) componentElement.getOwnerDocument().importNode(
			    help, true);
			componentElement.appendChild(help);
			helpOutput = helpOutputXPath.getNode(componentElement);

			replaceAttributesByExpression(helpOutput, "messageKey",
			    componentKey + "-help");
		}

		putLocalizedText(ref_s_att, null, null, helpOutput,
		    helpOutput.getOwnerDocument(), helpMsg);
	}

	public static boolean isLocalizationKeyCorrect(String loc_key) {
		return !StringUtil.isEmpty(loc_key)
		        && !loc_key.contains(CoreConstants.SPACE);
	}

	public static String getElementsTextNodeValue(Node element) {

		NodeList children = element.getChildNodes();
		StringBuffer text_value = new StringBuffer();

		for (int i = 0; i < children.getLength(); i++) {

			Node child = children.item(i);

			if (child != null && child.getNodeType() == Node.TEXT_NODE) {
				String node_value = child.getNodeValue();

				if (node_value != null && node_value.length() > 0)
					text_value.append(node_value);
			}
		}

		return text_value.toString();
	}

	public static void setElementsTextNodeValue(Node element, String value) {

		NodeList children = element.getChildNodes();
		List<Node> childs_to_remove = new ArrayList<Node>();

		for (int i = 0; i < children.getLength(); i++) {

			Node child = children.item(i);

			if (child != null && child.getNodeType() == Node.TEXT_NODE)
				childs_to_remove.add(child);
		}

		for (Iterator<Node> iter = childs_to_remove.iterator(); iter.hasNext();)
			element.removeChild(iter.next());

		Node text_node = element.getOwnerDocument().createTextNode(value);
		element.appendChild(text_node);
	}

	/**
	 * <p>
	 *
	 * @param components_xml
	 *            - components xml document, which passes the structure described:
	 *            <p>
	 *            optional document root name - form_components
	 *            </p>
	 *            <p>
	 *            Component is encapsulated into div tag, which contains tag id as component type.
	 *            Every component div container is child of root.
	 *            </p>
	 *            <p>
	 *            Component type starts with "fbc_"
	 *            </p>
	 *            <p>
	 *            example:
	 *            </p>
	 *            <p>
	 *            &lt;form_components&gt;<br />
	 *            &lt;div class="input" id="fbc_text"&gt;<br />
	 *            &lt;label class="label" for="fbc_text-value" id="fbc_text-label"&gt; Single Line
	 *            Field &lt;/label&gt;<br />
	 *            &lt;input class="value" id="fbc_text-value" name="d_fbc_text" type="text" value=""
	 *            /&gt;<br />
	 *            &lt;/div&gt;<br />
	 *            &lt;/form_components&gt;
	 *            </p>
	 *            </p> IMPORTANT: types should be unique
	 * @return List of components types (Strings)
	 */
	public static List<String> gatherAvailableComponentsTypes(
	        Document components_xml) {

		Element root = components_xml.getDocumentElement();

		if (!root.hasChildNodes())
			return null;

		NodeList children = root.getChildNodes();
		List<String> components_types = new ArrayList<String>();

		for (int i = 0; i < children.getLength(); i++) {

			Node child = children.item(i);

			if (child.getNodeType() == Node.ELEMENT_NODE) {

				String element_id = ((Element) child)
				        .getAttribute(FormManagerUtil.id_att);

				if (element_id != null
				        && element_id.startsWith(FormManagerUtil.CTID)
				        && !components_types.contains(element_id))
					components_types.add(element_id);
			}
		}

		return components_types;
	}

	public static Element getItemElementById(Document item_doc, String item_id) {

		Element item = FormManagerUtil.getElementById(item_doc, item_id);
		if (item == null)
			return null;

		return DOMUtil.getFirstChildElement(item);
	}

	public static List<Element> getItemElementsById(Document item_doc,
	        String item_id) {

		Element item = FormManagerUtil.getElementById(item_doc, item_id);
		if (item == null)
			return null;

		@SuppressWarnings("unchecked")
		List<Element> childEls = DOMUtil.getChildElements(item);
		return childEls;
	}

	public static void removeTextNodes(Node node) {

		NodeList children = node.getChildNodes();
		List<Node> childs_to_remove = new ArrayList<Node>();

		for (int i = 0; i < children.getLength(); i++) {

			Node child = children.item(i);

			if (child.getNodeType() == Node.TEXT_NODE) {

				childs_to_remove.add(child);

			} else {

				if (child.hasChildNodes())
					removeTextNodes(child);
			}
		}

		for (Iterator<Node> iter = childs_to_remove.iterator(); iter.hasNext();) {
			node.removeChild(iter.next());
		}
	}

	private static OutputFormat getOutputFormat() {

		if (output_format == null) {

			OutputFormat output_format = new OutputFormat();
			output_format.setOmitXMLDeclaration(true);
			output_format.setLineSeparator(System.getProperty(line_sep));
			output_format.setIndent(4);
			output_format.setIndenting(true);
			output_format.setMediaType(xml_mediatype);
			output_format.setEncoding(utf_8_encoding);
			FormManagerUtil.output_format = output_format;
		}

		return output_format;
	}

	public static String serializeDocument(Document document)
	        throws IOException {

		StringWriter writer = new StringWriter();
		XMLSerializer serializer = new XMLSerializer(writer, getOutputFormat());
		serializer.asDOMSerializer();
		serializer.serialize(document.getDocumentElement());

		return writer.toString();
	}

	public static String escapeNonXmlTagSymbols(String string) {

		StringBuffer result = new StringBuffer();

		StringCharacterIterator iterator = new StringCharacterIterator(string);

		Character character = iterator.current();

		while (character != CharacterIterator.DONE) {

			if (non_xml_pattern.matcher(character.toString()).matches())
				result.append(character);

			character = iterator.next();
		}

		return result.toString();
	}

	public static int parseIdNumber(String id) {

		if (id == null)
			return 0;

		return Integer.parseInt(id.substring(CTID.length()));
	}

	private static final XPathUtil componentsContainerElementXPath = new XPathUtil(
	        ".//h:body//idega:switch", new Prefix("idega", idega_namespace));

	public static Element getComponentsContainerElement(Document xform) {

		Element container = componentsContainerElementXPath.getNode(xform);

		if (container == null) {
			XPathUtil xu = new XPathUtil(".//h:body//xf:switch");
			container = xu.getNode(xform);
		}

		return container;
	}

	private static Pattern componentIdPattern = Pattern.compile("fbc_[\\d]*");
	private static final XPathUtil allComponentsIdsXPath = new XPathUtil(
	        ".//@id[starts-with(., 'fbc_')]");

	public static Set<String> getAllComponentsIds(Document xform) {

		NodeList idsAttributes = allComponentsIdsXPath.getNodeset(xform);

		HashSet<String> ids = new HashSet<String>(idsAttributes.getLength());

		for (int i = 0; i < idsAttributes.getLength(); i++) {

			String idValue = idsAttributes.item(i).getNodeValue();

			if (componentIdPattern.matcher(idValue).matches()) {

				ids.add(idValue);
			}
		}

		return ids;
	}

	public static void replaceAttributesByExpression(Node context,
	        String expressionValue, String replaceWith) {

		String expressionValueForXPath = "#{" + expressionValue + "}";

		NodeList attributes;

		synchronized (replaceAttributesByExpressionXPath) {

			replaceAttributesByExpressionXPath.clearVariables();
			replaceAttributesByExpressionXPath.setVariable(expressionVariable,
			    expressionValueForXPath);

			attributes = replaceAttributesByExpressionXPath.getNodeset(context);
		}

		if (attributes != null) {

			String expressionValueForRegex = "#\\{" + expressionValue + "\\}";

			for (int i = 0; i < attributes.getLength(); i++) {

				Node attNode = attributes.item(i);
				String attValue = attNode.getNodeValue();
				attValue = attValue.replaceAll(expressionValueForRegex,
				    replaceWith);
				attNode.setNodeValue(attValue);
			}
		}
	}

	private static final XPathUtil getLocalizableElementsXPath = new XPathUtil(
	        ".//*[attribute::*[(name(.) = 'ref' or name(.) = 'value') and starts-with(., \"instance('localized_strings')/\")] ]");

	public static NodeList getLocalizableElements(Node context) {

		return getLocalizableElementsXPath.getNodeset(context);
	}

	public static void main(String[] args) {

		try {
			DocumentBuilder db = XmlUtil.getDocumentBuilder();
			Document d = db
			        .parse(new File(
			                "/Users/civilis/dev/workspace/eplatform-4-bpm/com.idega.xformsmanager/resources/templates/form-components.xhtml"));

			Element emailElement = getElementById(d, "fbc_email");

			Map<ErrorType, LocalizedStringBean> errStrs = getErrorLabelLocalizedStrings(emailElement);

			Element textElement = getElementById(d, "fbc_text");

			LocalizedStringBean sb = errStrs.get(ErrorType.validation);
			ErrorStringBean errstr = new ErrorStringBean(ErrorType.custom, sb);

			errstr.getLocalizedStringBean().setString(new Locale("en"),
			    "uhuauaha");

			setErrorLabelLocalizedStrings(emailElement, "dfdf", "asdfdsf",
			    errstr, d);

			setHelpTextLocalizedStrings(textElement, "asdfads",
			    errstr.getLocalizedStringBean(), d);

			DOMUtil.prettyPrintDOM(textElement.getOwnerDocument());

			if (true)
				return;

			XPathUtil xu = new XPathUtil(
			        ".//*/attribute::*[contains(., '#{componentId}')]");

			NodeList nodes = xu.getNodeset(emailElement);

			for (int i = 0; i < nodes.getLength(); i++) {

				Node attNode = nodes.item(i);
				String attValue = attNode.getNodeValue();
				attValue = attValue.replaceAll("#\\{componentId\\}", "_theID_");

				attNode.setNodeValue(attValue);
			}

			DOMUtil.prettyPrintDOM(emailElement);

		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public static void modifyFormForLocalisationInFormbuilder(
	        Document xforms_doc) {
		Element setvalue_element = getDataModelSetValueElement(xforms_doc);

		setvalue_element.getParentNode().removeChild(setvalue_element);
	}

	public static void modifyXFormsDocumentForViewing(Document xforms_doc) {

		// TODO: use better way. probably just xforms property, as it is done when viewing form in
		// pdf mode
		// the idea here seems that all pages need to be visible (as with pdf)

		NodeList tags = xforms_doc.getElementsByTagName(idegans_case_tag);
		Element switch_element = (Element) xforms_doc.getElementsByTagName(
		    idegans_switch_tag).item(0);

		Element switch_parent = (Element) switch_element.getParentNode();

		for (int i = 0; i < tags.getLength(); i++) {
			@SuppressWarnings("unchecked")
			List<Element> case_children = DOMUtil
			        .getChildElements(tags.item(i));
			for (Element case_child : case_children) {
				switch_parent.appendChild(case_child);
			}
		}

		switch_element.getParentNode().removeChild(switch_element);
	}

	public static Map<String, List<String>> getCategorizedComponentsTypes(
	        Document form_components_doc) {

		Element instance_element = getElementById(form_components_doc,
		    "component_categories");
		NodeList categories = instance_element.getElementsByTagName("category");
		Map<String, List<String>> categorized_types = new HashMap<String, List<String>>();

		for (int i = 0; i < categories.getLength(); i++) {

			Element category = (Element) categories.item(i);
			NodeList components = category.getElementsByTagName(component_tag);
			List<String> component_types = new ArrayList<String>();

			for (int j = 0; j < components.getLength(); j++) {

				Element component = (Element) components.item(j);
				component_types.add(component.getAttribute(component_id_att));
			}

			String category_name = category.getAttribute(name_att);
			categorized_types.put(category_name, component_types);
		}

		return categorized_types;
	}

	public static Element createAutofillInstance(Document xforms_doc) {

		Element inst_el = xforms_doc.createElement(instance_tag);
		inst_el.setAttribute(xmlns_att, "");
		inst_el.setAttribute(relevant_att, xpath_false);

		return inst_el;
	}

	public static void setFormTitle(Document xformsXmlDoc,
	        LocalizedStringBean formTitle) {

		Element output = getFormTitleOutputElement(xformsXmlDoc);
		putLocalizedText(ref_s_att, null, null, output, xformsXmlDoc, formTitle);
	}

	public static LocalizedStringBean getFormTitle(Document xformsDoc) {
		Element output = getFormTitleOutputElement(xformsDoc);
		return getElementLocalizedStrings(output, xformsDoc);
	}

	public static void setFormErrorMsg(Document xformsXmlDoc,
	        LocalizedStringBean formError) {

		Element message = getFormErrorMessageElement(xformsXmlDoc);

		message.removeAttribute(FormManagerUtil.model_att);

		putLocalizedText(ref_s_att, null, null, message, xformsXmlDoc,
		    formError);
	}

	public static LocalizedStringBean getFormErrorMsg(Document xformsDoc) {

		Element message = getFormErrorMessageElement(xformsDoc);
		return getElementLocalizedStrings(message, xformsDoc);
	}

	public static Element getFormInstanceModelElement(Document context) {

		return formInstanceModelElementXPath.getNode(context);
	}

	public static Element getDefaultFormModelElement(Document context) {

		return defaultFormModelElementXPath.getNode(context);
	}

	public static XPathUtil getFormModelElementByIdXPath() {

		return formModelElementXPath;
	}

	public static Element getSubmissionElement(Node context) {

		return submissionElementXPath.getNode(context);
	}

	public static Element getFormSubmissionInstanceElement(Document context) {

		return formSubmissionInstanceElementXPath.getNode(context);
	}

	public static Element getFormSubmissionInstanceDataElement(Node context) {

		return formSubmissionInstanceDataElementXPath.getNode(context);
	}

	public static Element getInstanceElement(Element context) {

		return instanceElementXPath.getNode(context);
	}

	public static XPathUtil getInstanceElementByIdXPath() {

		return instanceElementByIdXPath;
	}

	private static Element getFormTitleOutputElement(Node context) {
		Element title = formTitleOutputElementXPath.getNode(context);
		if (title == null)
			title = new XPathUtil(".//h:title//idega:output").getNode(context);
		return title;
	}

	private static Element getFormErrorMessageElement(Node context) {

		return formErrorMessageXPath.getNode(context);
	}

	public static String getFormId(Node xformsDoc) {
		return XFormsUtil.getFormId(xformsDoc);
	}

	public static void setFormId(Document xformsDoc, String formId) {
		XFormsUtil.setFormId(xformsDoc, formId);
	}

	public static Element getLocalizedStringElement(Node context) {

		return localizedStringElementXPath.getNode(context);
	}

	public static Element getElementById(Node context, String id) {

		synchronized (elementByIdXPath) {

			elementByIdXPath.clearVariables();
			elementByIdXPath.setVariable(id_att, id);
			return elementByIdXPath.getNode(context);
		}
	}

	public static Element getFormParamsElement(Node context) {

		return formParamsXPath.getNode(context);
	}

	public static Element createFormParamsElement(Element context,
	        boolean appendToContext) {

		Element el = context.getOwnerDocument().createElement("params");
		el.setAttribute(nodeTypeAtt, "formParams");

		if (appendToContext) {
			el = (Element) context.appendChild(el);
		}

		return el;
	}

	/**
	 * @param context
	 *            node to start looking from
	 * @param elementName
	 *            optional
	 * @param attributeName
	 *            optional
	 * @return
	 */
	public static NodeList getElementsContainingAttribute(Node context,
	        String elementName, String attributeName) {

		if (StringUtil.isEmpty(elementName))
			elementName = CoreConstants.STAR;

		if (StringUtil.isEmpty(attributeName))
			attributeName = CoreConstants.STAR;

		XPathUtil elementsContainingAttributeXPath = new XPathUtil(
		        ".//*[($elementName = '*' or name(.) = $elementName) and ($attributeName = '*' or attribute::*[name(.) = $attributeName])]");

		synchronized (elementsContainingAttributeXPath) {

			elementsContainingAttributeXPath.clearVariables();
			elementsContainingAttributeXPath.setVariable(elementNameVariable,
			    elementName);
			elementsContainingAttributeXPath.setVariable(attributeNameVariable,
			    attributeName);

			return elementsContainingAttributeXPath.getNodeset(context);
		}
	}

	/**
	 * @param context
	 *            node to start looking from
	 * @param elementName
	 *            optional
	 * @param attributeName
	 *            optional
	 * @param attributeValue
	 *            optional
	 * @return
	 */
	public static NodeList getElementsContainingAttribute(Node context,
	        String elementName, String attributeName, String attributeValue) {

		if (StringUtil.isEmpty(elementName))
			elementName = CoreConstants.STAR;

		if (StringUtil.isEmpty(attributeName))
			attributeName = CoreConstants.STAR;

		if (attributeValue == null)
			attributeValue = CoreConstants.STAR;

		XPathUtil elementsContainingAttributeXPath = new XPathUtil(
		        ".//*[($elementName = '*' or name(.) = $elementName) and ($attributeName = '*' or attribute::*[name(.) = $attributeName]) "
		                + "and (attributeValue = '*' or attribute::*[. = $attributeValue])]");

		String attributeValueVariable = "attributeValue";

		synchronized (elementsContainingAttributeXPath) {

			elementsContainingAttributeXPath.clearVariables();
			elementsContainingAttributeXPath.setVariable(elementNameVariable,
			    elementName);
			elementsContainingAttributeXPath.setVariable(attributeNameVariable,
			    attributeName);
			elementsContainingAttributeXPath.setVariable(
			    attributeValueVariable, attributeValue);

			return elementsContainingAttributeXPath.getNodeset(context);
		}
	}

	private static Element getDataModelSetValueElement(Node context) {

		return localizaionSetValueElement.getNode(context);
	}

	public static Map<String, List<ComponentType>> getComponentsTypesByDatatype(
	        Document form_components_doc) {

		Element instance_element = getElementById(form_components_doc,
		    "components-datatypes-mappings");
		NodeList list = instance_element.getElementsByTagName("component");

		Map<String, List<ComponentType>> types = new HashMap<String, List<ComponentType>>();

		for (int i = 0; i < list.getLength(); i++) {

			Element component = (Element) list.item(i);
			String componentId = component.getAttribute(component_id_att);
			String accessSupport = component.getAttribute(accessSupport_att);
			ComponentType type = new ComponentType(componentId, accessSupport);

			NodeList datatypes = component.getElementsByTagName(datatype_tag);

			for (int j = 0; j < datatypes.getLength(); j++) {

				Element datatype = (Element) datatypes.item(j);
				String value = datatype.getTextContent();

				if (types.containsKey(value)) {
					types.get(value).add(type);
				} else {
					List<ComponentType> newList = new ArrayList<ComponentType>();
					newList.add(type);
					types.put(value, newList);
				}
			}
		}

		return types;
	}

	/**
	 * <p>
	 * Copies schema type from one schema document to another by provided type name.
	 * </p>
	 * <p>
	 * <b><i>WARNING: </i></b>currently doesn't support cascading types copying, i.e., when one type
	 * depends on another
	 * </p>
	 *
	 * @param src
	 *            - schema document to copy from
	 * @param dest
	 *            - schema document to copy to
	 * @param src_type_name
	 *            - name of type to copy
	 * @throws NullPointerException
	 *             - some params were null or such type was not found in src document
	 */
	public static void copySchemaType(Document src, Document dest,
	        String src_type_name, String dest_type_name)
	        throws NullPointerException {

		if (src == null || dest == null || src_type_name == null) {

			String err_msg = new StringBuilder(
			        "\nEither parameter is not provided:").append("\nsrc: ")
			        .append(String.valueOf(src)).append("\ndest: ")
			        .append(String.valueOf(dest)).append("\ntype_name: ")
			        .append(src_type_name).toString();

			throw new NullPointerException(err_msg);
		}

		Element root = src.getDocumentElement();

		// check among simple types

		Element type_to_copy = getSchemaTypeToCopy(
		    root.getElementsByTagName(simple_type), src_type_name);

		if (type_to_copy == null) {
			// check among complex types

			type_to_copy = getSchemaTypeToCopy(
			    root.getElementsByTagName(complex_type), src_type_name);
		}

		if (type_to_copy == null)
			throw new NullPointerException(
			        "Schema type was not found by provided name: "
			                + src_type_name);

		type_to_copy = (Element) dest.importNode(type_to_copy, true);
		type_to_copy.setAttribute(FormManagerUtil.name_att, dest_type_name);

		((Element) dest.getElementsByTagName(FormManagerUtil.schema_tag)
		        .item(0)).appendChild(type_to_copy);
	}

	private static Element getSchemaTypeToCopy(NodeList types,
	        String type_name_required) {

		for (int i = 0; i < types.getLength(); i++) {

			Element simple_type = (Element) types.item(i);
			String name_att = simple_type
			        .getAttribute(FormManagerUtil.name_att);

			if (name_att != null && name_att.equals(type_name_required))
				return simple_type;
		}

		return null;
	}

	public static LocalizedStringBean getDefaultErrorMessage(ErrorType errType,
	        Document templateDocument) {

		String key = "default_validation-" + errType;
		return getLocalizedStrings(key, templateDocument);
	}

	public static XPathUtil getLabelElementXPath() {
		return labelElementXPath;
	}

	public static NodeList getBindsByNodeset(Node context, String nodeset) {

		synchronized (bindsByNodesetXPath) {

			bindsByNodesetXPath.clearVariables();
			bindsByNodesetXPath.setVariable(nodesetVariable, nodeset);

			return bindsByNodesetXPath.getNodeset(context);
		}
	}
} public class InitializationException extends Exception {

	private static final long serialVersionUID = -472204824125054830L;

	public InitializationException(String message) {
		super("InitializationException: " + message);
	}
	
	public InitializationException(String message, Throwable e) {
		super("InitializationException: " + message, e);
	}
	
	public InitializationException(Throwable e) {
		super("InitializationException", e);
	}
}
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.chiba.xml.xslt.TransformerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;
import com.idega.idegaweb.IWMainApplication;
import com.idega.xformsmanager.business.DocumentManager;
import com.idega.xformsmanager.business.PersistedFormDocument;
import com.idega.xformsmanager.business.PersistenceManager;
import com.idega.xformsmanager.business.XFormPersistenceType;
import com.idega.xformsmanager.business.component.ConstComponentCategory;
import com.idega.xformsmanager.component.FormDocument;
import com.idega.xformsmanager.component.beans.LocalizedStringBean;
import com.idega.xformsmanager.component.datatypes.ComponentType;
import com.idega.xformsmanager.component.datatypes.ConstComponentDatatype;
import com.idega.xformsmanager.component.impl.FormComponentFactory;
import com.idega.xformsmanager.component.impl.FormDocumentImpl;
import com.idega.xformsmanager.component.impl.FormDocumentTemplateImpl;
import com.idega.xformsmanager.context.DMContext;
import com.idega.xformsmanager.generator.ComponentsGenerator;
import com.idega.xformsmanager.manager.HtmlManagerFactory;
import com.idega.xformsmanager.manager.XFormsManagerFactory;
import com.idega.xformsmanager.util.FormManagerUtil;
import com.idega.xformsmanager.util.InitializationException;
			logger.info("FormManager initialized in: " + (end - start));
			
		} catch (Exception e) {
			
			logger
			        .log(
			            Level.SEVERE,
			            "Could not initialize FormManager. See \"caused by\" for details.",
			            e);
			throw new InitializationException(
			        "Could not initialize FormManager. See \"caused by\" for details.",
			        e);
		}
	}
	
	public boolean isInited() {
		return inited;
	}
	
	public TransformerService getTransformerService() {
		return transformerService;
	}
	
	public void setTransformerService(TransformerService transformerService) {
		this.transformerService = transformerService;
	}
	
	public CacheManager getCacheManager() {
		return cacheManager;
	}
	
	public void setCacheManager(CacheManager cacheManager) {
		this.cacheManager = cacheManager;
	}
	
	public PersistenceManager getPersistenceManager() {
		return persistenceManager;
	}
	
	@Autowired
	@XFormPersistenceType("slide")
	public void setPersistenceManager(PersistenceManager persistenceManager) {
		this.persistenceManager = persistenceManager;
	}
	
	public Document getComponentsXforms() {
		return componentsXforms;
	}
	
	public void setComponentsXforms(Document componentsXforms) {
		this.componentsXforms = componentsXforms;
	}
	
	public Document getComponentsXsd() {
		return componentsXsd;
	}
	
	public void setComponentsXsd(Document componentsXsd) {
		this.componentsXsd = componentsXsd;
	}
	
	public Document getFormXformsTemplate() {
		return formXformsTemplate;
	}
	
	public void setFormXformsTemplate(Document formXformsTemplate) {
		this.formXformsTemplate = formXformsTemplate;
	}
	
	public XFormsManagerFactory getXformsManagerFactory() {
		return xformsManagerFactory;
	}
	
	public void setXformsManagerFactory(
	        XFormsManagerFactory xformsManagerFactory) {
		this.xformsManagerFactory = xformsManagerFactory;
	}
	
	public HtmlManagerFactory getHtmlManagerFactory() {
		return htmlManagerFactory;
	}
	
	public void setHtmlManagerFactory(HtmlManagerFactory htmlManagerFactory) {
		this.htmlManagerFactory = htmlManagerFactory;
	}
	
	FormComponentFactory getFormComponentFactory() {
		return formComponentFactory;
	}
	
	void setFormComponentFactory(FormComponentFactory formComponentFactory) {
		this.formComponentFactory = formComponentFactory;
	}
	
	DMContext getDMContext() {
		return DMContext;
	}
	
	private FormDocumentImpl createFormDocument() {
		
		return new FormDocumentImpl();
	}
	
	protected PersistedFormDocument loadPersistedFormDocument(
	        DMContext context, Long formId) {
		
		PersistenceManager persistenceManager = context.getPersistenceManager();
		return persistenceManager.loadForm(formId);
	}
	
	protected PersistedFormDocument takeAndloadFormDocument(DMContext context,
	        Long formIdToTakeFrom) {
		
		PersistenceManager persistenceManager = context.getPersistenceManager();
		return persistenceManager.takeForm(formIdToTakeFrom);
	}
	
	public FormDocument getFormDocumentTemplate() {
		
		// TODO: use as singleton
		FormDocumentTemplateImpl template = new FormDocumentTemplateImpl();